home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclVar.c < prev   
Encoding:
C/C++ Source or Header  |  1997-08-15  |  136.8 KB  |  4,493 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclVar.c --
  3.  *
  4.  *    This file contains routines that implement Tcl variables
  5.  *    (both scalars and arrays).
  6.  *
  7.  *    The implementation of arrays is modelled after an initial
  8.  *    implementation by Mark Diekhans and Karl Lehenbauer.
  9.  *
  10.  * Copyright (c) 1987-1994 The Regents of the University of California.
  11.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  12.  *
  13.  * See the file "license.terms" for information on usage and redistribution
  14.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  15.  *
  16.  * SCCS: @(#) tclVar.c 1.125 97/08/06 14:47:55
  17.  */
  18.  
  19. #include "tclInt.h"
  20. #include "tclPort.h"
  21.  
  22. /*
  23.  * The strings below are used to indicate what went wrong when a
  24.  * variable access is denied.
  25.  */
  26.  
  27. static char *noSuchVar =    "no such variable";
  28. static char *isArray =        "variable is array";
  29. static char *needArray =    "variable isn't array";
  30. static char *noSuchElement =    "no such element in array";
  31. static char *danglingUpvar =    "upvar refers to element in deleted array";
  32. static char *badNamespace =    "parent namespace doesn't exist";
  33. static char *missingName =    "missing variable name";
  34.  
  35. /*
  36.  * Forward references to procedures defined later in this file:
  37.  */
  38.  
  39. static  char *        CallTraces _ANSI_ARGS_((Interp *iPtr, Var *arrayPtr,
  40.                 Var *varPtr, char *part1, char *part2,
  41.                 int flags));
  42. static void        CleanupVar _ANSI_ARGS_((Var *varPtr,
  43.                 Var *arrayPtr));
  44. static void        DeleteSearches _ANSI_ARGS_((Var *arrayVarPtr));
  45. static void        DeleteArray _ANSI_ARGS_((Interp *iPtr,
  46.                 char *arrayName, Var *varPtr, int flags));
  47. static int        MakeUpvar _ANSI_ARGS_((
  48.                 Interp *iPtr, CallFrame *framePtr,
  49.                 char *otherP1, char *otherP2, int otherFlags,
  50.                 char *myName, int myFlags));
  51. static Var *        NewVar _ANSI_ARGS_((void));
  52. static ArraySearch *    ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp,
  53.                 Var *varPtr, char *varName, char *string));
  54. static void        VarErrMsg _ANSI_ARGS_((Tcl_Interp *interp,
  55.                 char *part1, char *part2, char *operation,
  56.                 char *reason));
  57.  
  58. /*
  59.  *----------------------------------------------------------------------
  60.  *
  61.  * TclLookupVar --
  62.  *
  63.  *    This procedure is used by virtually all of the variable code to
  64.  *    locate a variable given its name(s).
  65.  *
  66.  * Results:
  67.  *    The return value is a pointer to the variable structure indicated by
  68.  *    part1 and part2, or NULL if the variable couldn't be found. If the
  69.  *    variable is found, *arrayPtrPtr is filled in with the address of the
  70.  *    variable structure for the array that contains the variable (or NULL
  71.  *    if the variable is a scalar). If the variable can't be found and
  72.  *    either createPart1 or createPart2 are 1, a new as-yet-undefined
  73.  *    (VAR_UNDEFINED) variable structure is created, entered into a hash
  74.  *    table, and returned.
  75.  *
  76.  *    If the variable isn't found and creation wasn't specified, or some
  77.  *    other error occurs, NULL is returned and an error message is left in
  78.  *    interp->result if TCL_LEAVE_ERR_MSG is set in flags. (The result
  79.  *    isn't put in interp->objResultPtr because this procedure is used
  80.  *    by so many string-based routines.)
  81.  *
  82.  *    Note: it's possible for the variable returned to be VAR_UNDEFINED
  83.  *    even if createPart1 or createPart2 are 1 (these only cause the hash
  84.  *    table entry or array to be created). For example, the variable might
  85.  *    be a global that has been unset but is still referenced by a
  86.  *    procedure, or a variable that has been unset but it only being kept
  87.  *    in existence (if VAR_UNDEFINED) by a trace.
  88.  *
  89.  * Side effects:
  90.  *    New hashtable entries may be created if createPart1 or createPart2
  91.  *    are 1.
  92.  *
  93.  *----------------------------------------------------------------------
  94.  */
  95.  
  96. Var *
  97. TclLookupVar(interp, part1, part2, flags, msg, createPart1, createPart2,
  98.         arrayPtrPtr)
  99.     Tcl_Interp *interp;        /* Interpreter to use for lookup. */
  100.     char *part1;        /* If part2 isn't NULL, this is the name of
  101.                  * an array. Otherwise, if the
  102.                  * TCL_PARSE_PART1 flag bit is set this
  103.                  * is a full variable name that could
  104.                  * include a parenthesized array elemnt. If
  105.                  * TCL_PARSE_PART1 isn't present, then
  106.                  * this is the name of a scalar variable. */
  107.     char *part2;        /* Name of element within array, or NULL. */
  108.     int flags;            /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  109.                  * TCL_LEAVE_ERR_MSG, and
  110.                  * TCL_PARSE_PART1 bits matter. */
  111.     char *msg;            /* Verb to use in error messages, e.g.
  112.                  * "read" or "set". Only needed if
  113.                  * TCL_LEAVE_ERR_MSG is set in flags. */
  114.     int createPart1;        /* If 1, create hash table entry for part 1
  115.                  * of name, if it doesn't already exist. If
  116.                  * 0, return error if it doesn't exist. */
  117.     int createPart2;        /* If 1, create hash table entry for part 2
  118.                  * of name, if it doesn't already exist. If
  119.                  * 0, return error if it doesn't exist. */
  120.     Var **arrayPtrPtr;        /* If the name refers to an element of an
  121.                  * array, *arrayPtrPtr gets filled in with
  122.                  * address of array variable. Otherwise
  123.                  * this is set to NULL. */
  124. {
  125.     Interp *iPtr = (Interp *) interp;
  126.     CallFrame *varFramePtr = iPtr->varFramePtr;
  127.                 /* Points to the procedure call frame whose
  128.                  * variables are currently in use. Same as
  129.                  * the current procedure's frame, if any,
  130.                  * unless an "uplevel" is executing. */
  131.     Tcl_HashTable *tablePtr;    /* Points to the hashtable, if any, in which
  132.                  * to look up the variable. */
  133.     Tcl_Var var;                /* Used to search for global names. */
  134.     Var *varPtr;        /* Points to the Var structure returned for
  135.                      * the variable. */
  136.     char *elName;        /* Name of array element or NULL; may be
  137.                  * same as part2, or may be openParen+1. */
  138.     char *openParen, *closeParen;
  139.                                 /* If this procedure parses a name into
  140.                  * array and index, these point to the
  141.                  * parens around the index.  Otherwise they
  142.                  * are NULL. These are needed to restore
  143.                  * the parens after parsing the name. */
  144.     Namespace *varNsPtr, *dummy1Ptr, *dummy2Ptr;
  145.     Tcl_HashEntry *hPtr;
  146.     register char *p;
  147.     int new, i, result;
  148.  
  149.     varPtr = NULL;
  150.     *arrayPtrPtr = NULL;
  151.     openParen = closeParen = NULL;
  152.     varNsPtr = NULL;        /* set non-NULL if a nonlocal variable */
  153.  
  154.     /*
  155.      * If the name hasn't been parsed into array name and index yet,
  156.      * do it now.
  157.      */
  158.  
  159.     elName = part2;
  160.     if (flags & TCL_PARSE_PART1) {
  161.     for (p = part1; ; p++) {
  162.         if (*p == 0) {
  163.         elName = NULL;
  164.         break;
  165.         }
  166.         if (*p == '(') {
  167.         openParen = p;
  168.         do {
  169.             p++;
  170.         } while (*p != '\0');
  171.         p--;
  172.         if (*p == ')') {
  173.             closeParen = p;
  174.             *openParen = 0;
  175.             elName = openParen+1;
  176.         } else {
  177.             openParen = NULL;
  178.             elName = NULL;
  179.         }
  180.         break;
  181.         }
  182.     }
  183.     }
  184.  
  185.     /*
  186.      * Look up part1. Look it up as either a namespace variable or as a
  187.      * local variable in a procedure call frame (varFramePtr).
  188.      * Interpret part1 as a namespace variable if:
  189.      *    1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag,
  190.      *    2) there is no active frame (we're at the global :: scope),
  191.      *    3) the active frame was pushed to define the namespace context
  192.      *       for a "namespace eval" or "namespace inscope" command,
  193.      *    4) the name has namespace qualifiers ("::"s).
  194.      * Otherwise, if part1 is a local variable, search first in the
  195.      * frame's array of compiler-allocated local variables, then in its
  196.      * hashtable for runtime-created local variables.
  197.      *
  198.      * If createPart1 and the variable isn't found, create the variable and,
  199.      * if necessary, create varFramePtr's local var hashtable.
  200.      */
  201.  
  202.     if (((flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) != 0)
  203.             || (varFramePtr == NULL)
  204.             || !varFramePtr->isProcCallFrame
  205.             || (strstr(part1, "::") != NULL)) {
  206.     char *tail;
  207.     
  208.     var = Tcl_FindNamespaceVar(interp, part1, (Tcl_Namespace *) NULL,
  209.             flags);
  210.     if (var != (Tcl_Var) NULL) {
  211.             varPtr = (Var *) var;
  212.         }
  213.     if (varPtr == NULL) {
  214.         if (flags & TCL_LEAVE_ERR_MSG) {
  215.         Tcl_ResetResult(interp);
  216.         }
  217.         if (createPart1) {   /* var wasn't found so create it  */
  218.         result = TclGetNamespaceForQualName(interp, part1,
  219.                 (Namespace *) NULL, flags, &varNsPtr, &dummy1Ptr,
  220.             &dummy2Ptr, &tail);
  221.         if (result != TCL_OK) {
  222.             if (flags & TCL_LEAVE_ERR_MSG) {
  223.             /*
  224.              * Move the interpreter's object result to the
  225.              * string result, then reset the object result.
  226.              * FAILS IF OBJECT RESULT'S STRING REP HAS NULLS.
  227.              */
  228.             
  229.             Tcl_SetResult(interp,
  230.                             TclGetStringFromObj(Tcl_GetObjResult(interp),
  231.                     (int *) NULL),
  232.                             TCL_VOLATILE);
  233.             }
  234.             goto done;
  235.         }
  236.         if (varNsPtr == NULL) {
  237.             if (flags & TCL_LEAVE_ERR_MSG) {
  238.             VarErrMsg(interp, part1, part2, msg, badNamespace);
  239.             }
  240.             goto done;
  241.         }
  242.         if (tail == NULL) {
  243.             if (flags & TCL_LEAVE_ERR_MSG) {
  244.             VarErrMsg(interp, part1, part2, msg, missingName);
  245.             }
  246.             goto done;
  247.         }
  248.         hPtr = Tcl_CreateHashEntry(&varNsPtr->varTable, tail, &new);
  249.         varPtr = NewVar();
  250.         Tcl_SetHashValue(hPtr, varPtr);
  251.         varPtr->hPtr = hPtr;
  252.         varPtr->nsPtr = varNsPtr;
  253.         } else {        /* var wasn't found and not to create it */
  254.         if (flags & TCL_LEAVE_ERR_MSG) {
  255.             VarErrMsg(interp, part1, part2, msg, noSuchVar);
  256.         }
  257.         goto done;
  258.         }
  259.     }
  260.     } else {            /* local var: look in frame varFramePtr */
  261.     Proc *procPtr = varFramePtr->procPtr;
  262.     int localCt = procPtr->numCompiledLocals;
  263.     CompiledLocal *localPtr = procPtr->firstLocalPtr;
  264.     Var *localVarPtr = varFramePtr->compiledLocals;
  265.     int part1Len = strlen(part1);
  266.     
  267.     for (i = 0;  i < localCt;  i++) {
  268.         if (!localPtr->isTemp) {
  269.         char *localName = localVarPtr->name;
  270.         if ((part1[0] == localName[0])
  271.                 && (part1Len == localPtr->nameLength)
  272.                 && (strcmp(part1, localName) == 0)) {
  273.             varPtr = localVarPtr;
  274.             break;
  275.         }
  276.         }
  277.         localVarPtr++;
  278.         localPtr = localPtr->nextPtr;
  279.     }
  280.     if (varPtr == NULL) {    /* look in the frame's var hash table */
  281.         tablePtr = varFramePtr->varTablePtr;
  282.         if (createPart1) {
  283.         if (tablePtr == NULL) {
  284.             tablePtr = (Tcl_HashTable *)
  285.                 ckalloc(sizeof(Tcl_HashTable));
  286.             Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS);
  287.             varFramePtr->varTablePtr = tablePtr;
  288.         }
  289.         hPtr = Tcl_CreateHashEntry(tablePtr, part1, &new);
  290.         if (new) {
  291.             varPtr = NewVar();
  292.             Tcl_SetHashValue(hPtr, varPtr);
  293.             varPtr->hPtr = hPtr;
  294.                     varPtr->nsPtr = NULL; /* a local variable */
  295.         } else {
  296.             varPtr = (Var *) Tcl_GetHashValue(hPtr);
  297.         }
  298.         } else {
  299.         hPtr = NULL;
  300.         if (tablePtr != NULL) {
  301.             hPtr = Tcl_FindHashEntry(tablePtr, part1);
  302.         }
  303.         if (hPtr == NULL) {
  304.             if (flags & TCL_LEAVE_ERR_MSG) {
  305.             VarErrMsg(interp, part1, part2, msg, noSuchVar);
  306.             }
  307.             goto done;
  308.         }
  309.         varPtr = (Var *) Tcl_GetHashValue(hPtr);
  310.         }
  311.     }
  312.     }
  313.     if (openParen != NULL) {
  314.     *openParen = '(';
  315.     openParen = NULL;
  316.     }
  317.  
  318.     /*
  319.      * If varPtr is a link variable, we have a reference to some variable
  320.      * that was created through an "upvar" or "global" command. Traverse
  321.      * through any links until we find the referenced variable.
  322.      */
  323.     
  324.     while (TclIsVarLink(varPtr)) {
  325.     varPtr = varPtr->value.linkPtr;
  326.     }
  327.  
  328.     /*
  329.      * If we're not dealing with an array element, return varPtr.
  330.      */
  331.     
  332.     if (elName == NULL) {
  333.         goto done;
  334.     }
  335.  
  336.     /*
  337.      * We're dealing with an array element. Make sure the variable is an
  338.      * array and look up the element (create the element if desired).
  339.      */
  340.  
  341.     if (TclIsVarUndefined(varPtr) && !TclIsVarArrayElement(varPtr)) {
  342.     if (!createPart1) {
  343.         if (flags & TCL_LEAVE_ERR_MSG) {
  344.         VarErrMsg(interp, part1, part2, msg, noSuchVar);
  345.         }
  346.         varPtr = NULL;
  347.         goto done;
  348.     }
  349.     TclSetVarArray(varPtr);
  350.     TclClearVarUndefined(varPtr);
  351.     varPtr->value.tablePtr =
  352.             (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  353.     Tcl_InitHashTable(varPtr->value.tablePtr, TCL_STRING_KEYS);
  354.     } else if (!TclIsVarArray(varPtr)) {
  355.     if (flags & TCL_LEAVE_ERR_MSG) {
  356.         VarErrMsg(interp, part1, part2, msg, needArray);
  357.     }
  358.     varPtr = NULL;
  359.     goto done;
  360.     }
  361.     *arrayPtrPtr = varPtr;
  362.     if (closeParen != NULL) {
  363.     *closeParen = 0;
  364.     }
  365.     if (createPart2) {
  366.     hPtr = Tcl_CreateHashEntry(varPtr->value.tablePtr, elName, &new);
  367.     if (closeParen != NULL) {
  368.         *closeParen = ')';
  369.     }
  370.     if (new) {
  371.         if (varPtr->searchPtr != NULL) {
  372.         DeleteSearches(varPtr);
  373.         }
  374.         varPtr = NewVar();
  375.         Tcl_SetHashValue(hPtr, varPtr);
  376.         varPtr->hPtr = hPtr;
  377.         varPtr->nsPtr = varNsPtr;
  378.         TclSetVarArrayElement(varPtr);
  379.     }
  380.     } else {
  381.     hPtr = Tcl_FindHashEntry(varPtr->value.tablePtr, elName);
  382.     if (closeParen != NULL) {
  383.         *closeParen = ')';
  384.     }
  385.     if (hPtr == NULL) {
  386.         if (flags & TCL_LEAVE_ERR_MSG) {
  387.         VarErrMsg(interp, part1, part2, msg, noSuchElement);
  388.         }
  389.         varPtr = NULL;
  390.         goto done;
  391.     }
  392.     }
  393.     varPtr = (Var *) Tcl_GetHashValue(hPtr);
  394.  
  395.     done:
  396.     if (openParen != NULL) {
  397.         *openParen = '(';
  398.     }
  399.     return varPtr;
  400. }
  401.  
  402. /*
  403.  *----------------------------------------------------------------------
  404.  *
  405.  * Tcl_GetVar --
  406.  *
  407.  *    Return the value of a Tcl variable as a string.
  408.  *
  409.  * Results:
  410.  *    The return value points to the current value of varName as a string.
  411.  *    If the variable is not defined or can't be read because of a clash
  412.  *    in array usage then a NULL pointer is returned and an error message
  413.  *    is left in interp->result if the TCL_LEAVE_ERR_MSG flag is set.
  414.  *    Note: the return value is only valid up until the next change to the
  415.  *    variable; if you depend on the value lasting longer than that, then
  416.  *    make yourself a private copy.
  417.  *
  418.  * Side effects:
  419.  *    None.
  420.  *
  421.  *----------------------------------------------------------------------
  422.  */
  423.  
  424. char *
  425. Tcl_GetVar(interp, varName, flags)
  426.     Tcl_Interp *interp;        /* Command interpreter in which varName is
  427.                  * to be looked up. */
  428.     char *varName;        /* Name of a variable in interp. */
  429.     int flags;            /* OR-ed combination of TCL_GLOBAL_ONLY,
  430.                  * TCL_NAMESPACE_ONLY or TCL_LEAVE_ERR_MSG
  431.                  * bits. */
  432. {
  433.     return Tcl_GetVar2(interp, varName, (char *) NULL,
  434.                (flags | TCL_PARSE_PART1));
  435. }
  436.  
  437. /*
  438.  *----------------------------------------------------------------------
  439.  *
  440.  * Tcl_GetVar2 --
  441.  *
  442.  *    Return the value of a Tcl variable as a string, given a two-part
  443.  *    name consisting of array name and element within array.
  444.  *
  445.  * Results:
  446.  *    The return value points to the current value of the variable given
  447.  *    by part1 and part2 as a string. If the specified variable doesn't
  448.  *    exist, or if there is a clash in array usage, then NULL is returned
  449.  *    and a message will be left in interp->result if the
  450.  *    TCL_LEAVE_ERR_MSG flag is set. Note: the return value is only valid
  451.  *    up until the next change to the variable; if you depend on the value
  452.  *    lasting longer than that, then make yourself a private copy.
  453.  *
  454.  * Side effects:
  455.  *    None.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459.  
  460. char *
  461. Tcl_GetVar2(interp, part1, part2, flags)
  462.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  463.                  * to be looked up. */
  464.     char *part1;        /* Name of an array (if part2 is non-NULL)
  465.                  * or the name of a variable. */
  466.     char *part2;        /* If non-NULL, gives the name of an element
  467.                  * in the array part1. */
  468.     int flags;            /* OR-ed combination of TCL_GLOBAL_ONLY,
  469.                  * TCL_NAMESPACE_ONLY, TCL_LEAVE_ERR_MSG,
  470.                                  * and TCL_PARSE_PART1 bits. */
  471. {
  472.     register Tcl_Obj *part1Ptr;
  473.     register Tcl_Obj *part2Ptr = NULL;
  474.     Tcl_Obj *objPtr;
  475.     int length;
  476.  
  477.     length = strlen(part1);
  478.     TclNewObj(part1Ptr);
  479.     TclInitStringRep(part1Ptr, part1, length);
  480.     Tcl_IncrRefCount(part1Ptr);
  481.  
  482.     if (part2 != NULL) {
  483.         length = strlen(part2);
  484.         TclNewObj(part2Ptr);
  485.         TclInitStringRep(part2Ptr, part2, length);
  486.     Tcl_IncrRefCount(part2Ptr);
  487.     }
  488.     
  489.     objPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);
  490.     
  491.     TclDecrRefCount(part1Ptr);        /* done with the part1 name object */
  492.     if (part2Ptr != NULL) {
  493.     TclDecrRefCount(part2Ptr);  /* and the part2 name object */
  494.     }
  495.     
  496.     if (objPtr == NULL) {
  497.     /*
  498.      * Move the interpreter's object result to the string result, 
  499.      * then reset the object result.
  500.      * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
  501.      */
  502.  
  503.     Tcl_SetResult(interp,
  504.             TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL),
  505.             TCL_VOLATILE);
  506.     return NULL;
  507.     }
  508.  
  509.     /*
  510.      * THIS FAILS IF Tcl_ObjGetVar2's RESULT'S STRING REP HAS A NULL BYTE.
  511.      */
  512.     
  513.     return TclGetStringFromObj(objPtr, (int *) NULL);
  514. }
  515.  
  516. /*
  517.  *----------------------------------------------------------------------
  518.  *
  519.  * Tcl_ObjGetVar2 --
  520.  *
  521.  *    Return the value of a Tcl variable as a Tcl object, given a
  522.  *    two-part name consisting of array name and element within array.
  523.  *
  524.  * Results:
  525.  *    The return value points to the current object value of the variable
  526.  *    given by part1Ptr and part2Ptr. If the specified variable doesn't
  527.  *    exist, or if there is a clash in array usage, then NULL is returned
  528.  *    and a message will be left in the interpreter's result if the
  529.  *    TCL_LEAVE_ERR_MSG flag is set.
  530.  *
  531.  * Side effects:
  532.  *    The ref count for the returned object is _not_ incremented to
  533.  *    reflect the returned reference; if you want to keep a reference to
  534.  *    the object you must increment its ref count yourself.
  535.  *
  536.  *----------------------------------------------------------------------
  537.  */
  538.  
  539. Tcl_Obj *
  540. Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags)
  541.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  542.                  * to be looked up. */
  543.     register Tcl_Obj *part1Ptr;    /* Points to an object holding the name of
  544.                  * an array (if part2 is non-NULL) or the
  545.                  * name of a variable. */
  546.     register Tcl_Obj *part2Ptr;    /* If non-null, points to an object holding
  547.                  * the name of an element in the array
  548.                  * part1Ptr. */
  549.     int flags;            /* OR-ed combination of TCL_GLOBAL_ONLY,
  550.                  * TCL_LEAVE_ERR_MSG, and
  551.                  * TCL_PARSE_PART1 bits. */
  552. {
  553.     Interp *iPtr = (Interp *) interp;
  554.     register Var *varPtr;
  555.     Var *arrayPtr;
  556.     char *part1, *msg;
  557.     char *part2 = NULL;
  558.  
  559.     /*
  560.      * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
  561.      */
  562.  
  563.     part1 = TclGetStringFromObj(part1Ptr, (int *) NULL);
  564.     if (part2Ptr != NULL) {
  565.     part2 = TclGetStringFromObj(part2Ptr, (int *) NULL);
  566.     }
  567.     varPtr = TclLookupVar(interp, part1, part2, flags, "read",
  568.             /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr);
  569.     if (varPtr == NULL) {
  570.     return NULL;
  571.     }
  572.  
  573.     /*
  574.      * Invoke any traces that have been set for the variable.
  575.      */
  576.  
  577.     if ((varPtr->tracePtr != NULL)
  578.         || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  579.     msg = CallTraces(iPtr, arrayPtr, varPtr, part1, part2,
  580.         (flags & (TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY|TCL_PARSE_PART1)) | TCL_TRACE_READS);
  581.     if (msg != NULL) {
  582.         if (flags & TCL_LEAVE_ERR_MSG) {
  583.         VarErrMsg(interp, part1, part2, "read", msg);
  584.         }
  585.         goto errorReturn;
  586.     }
  587.     }
  588.  
  589.     /*
  590.      * Return the element if it's an existing scalar variable.
  591.      */
  592.     
  593.     if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
  594.     return varPtr->value.objPtr;
  595.     }
  596.     
  597.     if (flags & TCL_LEAVE_ERR_MSG) {
  598.     if (TclIsVarUndefined(varPtr) && (arrayPtr != NULL)
  599.             && !TclIsVarUndefined(arrayPtr)) {
  600.         msg = noSuchElement;
  601.     } else if (TclIsVarArray(varPtr)) {
  602.         msg = isArray;
  603.     } else {
  604.         msg = noSuchVar;
  605.     }
  606.     VarErrMsg(interp, part1, part2, "read", msg);
  607.     }
  608.  
  609.     /*
  610.      * An error. If the variable doesn't exist anymore and no-one's using
  611.      * it, then free up the relevant structures and hash table entries.
  612.      */
  613.  
  614.     errorReturn:
  615.     if (TclIsVarUndefined(varPtr)) {
  616.     CleanupVar(varPtr, arrayPtr);
  617.     }
  618.     return NULL;
  619. }
  620.  
  621. /*
  622.  *----------------------------------------------------------------------
  623.  *
  624.  * TclGetIndexedScalar --
  625.  *
  626.  *    Return the Tcl object value of a local scalar variable in the active
  627.  *    procedure, given its index in the procedure's array of compiler
  628.  *    allocated local variables.
  629.  *
  630.  * Results:
  631.  *    The return value points to the current object value of the variable
  632.  *    given by localIndex. If the specified variable doesn't exist, or
  633.  *    there is a clash in array usage, or an error occurs while executing
  634.  *    variable traces, then NULL is returned and a message will be left in
  635.  *    the interpreter's result if leaveErrorMsg is 1.
  636.  *
  637.  * Side effects:
  638.  *    The ref count for the returned object is _not_ incremented to
  639.  *    reflect the returned reference; if you want to keep a reference to
  640.  *    the object you must increment its ref count yourself.
  641.  *
  642.  *----------------------------------------------------------------------
  643.  */
  644.  
  645. Tcl_Obj *
  646. TclGetIndexedScalar(interp, localIndex, leaveErrorMsg)
  647.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  648.                  * to be looked up. */
  649.     int localIndex;        /* Index of variable in procedure's array
  650.                  * of local variables. */
  651.     int leaveErrorMsg;        /* 1 if to leave an error message in
  652.                  * interpreter's result on an error.
  653.                  * Otherwise no error message is left. */
  654. {
  655.     Interp *iPtr = (Interp *) interp;
  656.     CallFrame *varFramePtr = iPtr->varFramePtr;
  657.                 /* Points to the procedure call frame whose
  658.                  * variables are currently in use. Same as
  659.                  * the current procedure's frame, if any,
  660.                  * unless an "uplevel" is executing. */
  661.     Var *compiledLocals = varFramePtr->compiledLocals;
  662.     Var *varPtr;        /* Points to the variable's in-frame Var
  663.                  * structure. */
  664.     char *varName;        /* Name of the local variable. */
  665.     char *msg;
  666.  
  667. #ifdef TCL_COMPILE_DEBUG
  668.     Proc *procPtr = varFramePtr->procPtr;
  669.     int localCt = procPtr->numCompiledLocals;
  670.  
  671.     if (compiledLocals == NULL) {
  672.     fprintf(stderr, "\nTclGetIndexedScalar: can't get local %i in frame 0x%x, no compiled locals\n",
  673.             localIndex, (unsigned int) varFramePtr);
  674.     panic("TclGetIndexedScalar: no compiled locals in frame 0x%x",
  675.           (unsigned int) varFramePtr);
  676.     }
  677.     if ((localIndex < 0) || (localIndex >= localCt)) {
  678.     fprintf(stderr, "\nTclGetIndexedScalar: can't get local %i in frame 0x%x with %i locals\n",
  679.             localIndex, (unsigned int) varFramePtr, localCt);
  680.     panic("TclGetIndexedScalar: bad local index %i in frame 0x%x",
  681.           localIndex, (unsigned int) varFramePtr);
  682.     }
  683. #endif /* TCL_COMPILE_DEBUG */
  684.     
  685.     varPtr = &(compiledLocals[localIndex]);
  686.     varName = varPtr->name;
  687.  
  688.     /*
  689.      * If varPtr is a link variable, we have a reference to some variable
  690.      * that was created through an "upvar" or "global" command, or we have a
  691.      * reference to a variable in an enclosing namespace. Traverse through
  692.      * any links until we find the referenced variable.
  693.      */
  694.     
  695.     while (TclIsVarLink(varPtr)) {
  696.     varPtr = varPtr->value.linkPtr;
  697.     }
  698.  
  699.     /*
  700.      * Invoke any traces that have been set for the variable.
  701.      */
  702.  
  703.     if (varPtr->tracePtr != NULL) {
  704.     msg = CallTraces(iPtr, /*arrayPtr*/ NULL, varPtr, varName, NULL,
  705.             TCL_TRACE_READS);
  706.     if (msg != NULL) {
  707.         if (leaveErrorMsg) {
  708.         VarErrMsg(interp, varName, NULL, "read", msg);
  709.         }
  710.         return NULL;
  711.     }
  712.     }
  713.  
  714.     /*
  715.      * Make sure we're dealing with a scalar variable and not an array, and
  716.      * that the variable exists (isn't undefined).
  717.      */
  718.  
  719.     if (!TclIsVarScalar(varPtr) || TclIsVarUndefined(varPtr)) {
  720.     if (leaveErrorMsg) {
  721.         if (TclIsVarArray(varPtr)) {
  722.         msg = isArray;
  723.         } else {
  724.         msg = noSuchVar;
  725.         }
  726.         VarErrMsg(interp, varName, NULL, "read", msg);
  727.     }
  728.     return NULL;
  729.     }
  730.     return varPtr->value.objPtr;
  731. }
  732.  
  733. /*
  734.  *----------------------------------------------------------------------
  735.  *
  736.  * TclGetElementOfIndexedArray --
  737.  *
  738.  *    Return the Tcl object value for an element in a local array
  739.  *    variable. The element is named by the object elemPtr while the 
  740.  *    array is specified by its index in the active procedure's array
  741.  *    of compiler allocated local variables.
  742.  *
  743.  * Results:
  744.  *    The return value points to the current object value of the
  745.  *    element. If the specified array or element doesn't exist, or there
  746.  *    is a clash in array usage, or an error occurs while executing
  747.  *    variable traces, then NULL is returned and a message will be left in
  748.  *    the interpreter's result if leaveErrorMsg is 1.
  749.  *
  750.  * Side effects:
  751.  *    The ref count for the returned object is _not_ incremented to
  752.  *    reflect the returned reference; if you want to keep a reference to
  753.  *    the object you must increment its ref count yourself.
  754.  *
  755.  *----------------------------------------------------------------------
  756.  */
  757.  
  758. Tcl_Obj *
  759. TclGetElementOfIndexedArray(interp, localIndex, elemPtr, leaveErrorMsg)
  760.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  761.                  * to be looked up. */
  762.     int localIndex;        /* Index of array variable in procedure's
  763.                  * array of local variables. */
  764.     Tcl_Obj *elemPtr;        /* Points to an object holding the name of
  765.                  * an element to get in the array. */
  766.     int leaveErrorMsg;        /* 1 if to leave an error message in
  767.                  * the interpreter's result on an error.
  768.                  * Otherwise no error message is left. */
  769. {
  770.     Interp *iPtr = (Interp *) interp;
  771.     CallFrame *varFramePtr = iPtr->varFramePtr;
  772.                 /* Points to the procedure call frame whose
  773.                  * variables are currently in use. Same as
  774.                  * the current procedure's frame, if any,
  775.                  * unless an "uplevel" is executing. */
  776.     Var *compiledLocals = varFramePtr->compiledLocals;
  777.     Var *arrayPtr;        /* Points to the array's in-frame Var
  778.                  * structure. */
  779.     char *arrayName;        /* Name of the local array. */
  780.     Tcl_HashEntry *hPtr;
  781.     Var *varPtr = NULL;        /* Points to the element's Var structure
  782.                  * that we return. Initialized to avoid
  783.                  * compiler warning. */
  784.     char *elem, *msg;
  785.     int new;
  786.  
  787. #ifdef TCL_COMPILE_DEBUG
  788.     Proc *procPtr = varFramePtr->procPtr;
  789.     int localCt = procPtr->numCompiledLocals;
  790.  
  791.     if (compiledLocals == NULL) {
  792.     fprintf(stderr, "\nTclGetElementOfIndexedArray: can't get element of local %i in frame 0x%x, no compiled locals\n",
  793.             localIndex, (unsigned int) varFramePtr);
  794.     panic("TclGetIndexedScalar: no compiled locals in frame 0x%x",
  795.           (unsigned int) varFramePtr);
  796.     }
  797.     if ((localIndex < 0) || (localIndex >= localCt)) {
  798.     fprintf(stderr, "\nTclGetIndexedScalar: can't get element of local %i in frame 0x%x with %i locals\n",
  799.             localIndex, (unsigned int) varFramePtr, localCt);
  800.     panic("TclGetElementOfIndexedArray: bad local index %i in frame 0x%x",
  801.           localIndex, (unsigned int) varFramePtr);
  802.     }
  803. #endif /* TCL_COMPILE_DEBUG */
  804.  
  805.     /*
  806.      * THIS FAILS IF THE ELEMENT NAME OBJECT'S STRING REP HAS A NULL BYTE.
  807.      */
  808.     
  809.     elem = Tcl_GetStringFromObj(elemPtr, (int *) NULL);
  810.     arrayPtr = &(compiledLocals[localIndex]);
  811.     arrayName = arrayPtr->name;
  812.  
  813.     /*
  814.      * If arrayPtr is a link variable, we have a reference to some variable
  815.      * that was created through an "upvar" or "global" command, or we have a
  816.      * reference to a variable in an enclosing namespace. Traverse through
  817.      * any links until we find the referenced variable.
  818.      */
  819.     
  820.     while (TclIsVarLink(arrayPtr)) {
  821.     arrayPtr = arrayPtr->value.linkPtr;
  822.     }
  823.  
  824.     /*
  825.      * Make sure we're dealing with an array and that the array variable
  826.      * exists (isn't undefined).
  827.      */
  828.  
  829.     if (!TclIsVarArray(arrayPtr) || TclIsVarUndefined(arrayPtr)) {
  830.     if (leaveErrorMsg) {
  831.         VarErrMsg(interp, arrayName, elem, "read", noSuchVar);
  832.     }
  833.     goto errorReturn;
  834.     } 
  835.  
  836.     /*
  837.      * Look up the element. Note that we must create the element (but leave
  838.      * it marked undefined) if it does not already exist. This allows a
  839.      * trace to create new array elements "on the fly" that did not exist
  840.      * before. A trace is always passed a variable for the array element. If
  841.      * the trace does not define the variable, it will be deleted below (at
  842.      * errorReturn) and an error returned.
  843.      */
  844.  
  845.     hPtr = Tcl_CreateHashEntry(arrayPtr->value.tablePtr, elem, &new);
  846.     if (new) {
  847.     if (arrayPtr->searchPtr != NULL) {
  848.         DeleteSearches(arrayPtr);
  849.     }
  850.     varPtr = NewVar();
  851.     Tcl_SetHashValue(hPtr, varPtr);
  852.     varPtr->hPtr = hPtr;
  853.     varPtr->nsPtr = varFramePtr->nsPtr;
  854.     TclSetVarArrayElement(varPtr);
  855.     } else {
  856.     varPtr = (Var *) Tcl_GetHashValue(hPtr);
  857.     }
  858.  
  859.     /*
  860.      * Invoke any traces that have been set for the element variable.
  861.      */
  862.  
  863.     if ((varPtr->tracePtr != NULL)
  864.             || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  865.     msg = CallTraces(iPtr, arrayPtr, varPtr, arrayName, elem,
  866.             TCL_TRACE_READS);
  867.     if (msg != NULL) {
  868.         if (leaveErrorMsg) {
  869.         VarErrMsg(interp, arrayName, elem, "read", msg);
  870.         }
  871.         goto errorReturn;
  872.     }
  873.     }
  874.  
  875.     /*
  876.      * Return the element if it's an existing scalar variable.
  877.      */
  878.     
  879.     if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
  880.     return varPtr->value.objPtr;
  881.     }
  882.     
  883.     if (leaveErrorMsg) {
  884.     if (TclIsVarArray(varPtr)) {
  885.         msg = isArray;
  886.     } else {
  887.         msg = noSuchVar;
  888.     }
  889.     VarErrMsg(interp, arrayName, elem, "read", msg);
  890.     }
  891.  
  892.     /*
  893.      * An error. If the variable doesn't exist anymore and no-one's using
  894.      * it, then free up the relevant structures and hash table entries.
  895.      */
  896.  
  897.     errorReturn:
  898.     if ((varPtr != NULL) && TclIsVarUndefined(varPtr)) {
  899.     CleanupVar(varPtr, NULL); /* the array is not in a hashtable */
  900.     }
  901.     return NULL;
  902. }
  903.  
  904. /*
  905.  *----------------------------------------------------------------------
  906.  *
  907.  * Tcl_SetCmd --
  908.  *
  909.  *    This procedure is invoked to process the "set" Tcl command.
  910.  *    See the user documentation for details on what it does.
  911.  *
  912.  * Results:
  913.  *    A standard Tcl result value.
  914.  *
  915.  * Side effects:
  916.  *    A variable's value may be changed.
  917.  *
  918.  *----------------------------------------------------------------------
  919.  */
  920.  
  921.     /* ARGSUSED */
  922. int
  923. Tcl_SetCmd(dummy, interp, argc, argv)
  924.     ClientData dummy;            /* Not used. */
  925.     register Tcl_Interp *interp;    /* Current interpreter. */
  926.     int argc;                /* Number of arguments. */
  927.     char **argv;            /* Argument strings. */
  928. {
  929.     if (argc == 2) {
  930.     char *value;
  931.  
  932.     value = Tcl_GetVar2(interp, argv[1], (char *) NULL,
  933.         TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1);
  934.     if (value == NULL) {
  935.         return TCL_ERROR;
  936.     }
  937.     Tcl_SetResult(interp, value, TCL_VOLATILE);
  938.     return TCL_OK;
  939.     } else if (argc == 3) {
  940.     char *result;
  941.  
  942.     result = Tcl_SetVar2(interp, argv[1], (char *) NULL, argv[2],
  943.         TCL_LEAVE_ERR_MSG|TCL_PARSE_PART1);
  944.     if (result == NULL) {
  945.         return TCL_ERROR;
  946.     }
  947.     Tcl_SetResult(interp, result, TCL_VOLATILE);
  948.     return TCL_OK;
  949.     } else {
  950.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  951.         argv[0], " varName ?newValue?\"", (char *) NULL);
  952.     return TCL_ERROR;
  953.     }
  954. }
  955.  
  956. /*
  957.  *----------------------------------------------------------------------
  958.  *
  959.  * Tcl_SetVar --
  960.  *
  961.  *    Change the value of a variable.
  962.  *
  963.  * Results:
  964.  *    Returns a pointer to the malloc'ed string which is the character
  965.  *    representation of the variable's new value. The caller must not
  966.  *    modify this string. If the write operation was disallowed then NULL
  967.  *    is returned; if the TCL_LEAVE_ERR_MSG flag is set, then an
  968.  *    explanatory message will be left in interp->result. Note that the
  969.  *    returned string may not be the same as newValue; this is because
  970.  *    variable traces may modify the variable's value.
  971.  *
  972.  * Side effects:
  973.  *    If varName is defined as a local or global variable in interp,
  974.  *    its value is changed to newValue. If varName isn't currently
  975.  *    defined, then a new global variable by that name is created.
  976.  *
  977.  *----------------------------------------------------------------------
  978.  */
  979.  
  980. char *
  981. Tcl_SetVar(interp, varName, newValue, flags)
  982.     Tcl_Interp *interp;        /* Command interpreter in which varName is
  983.                  * to be looked up. */
  984.     char *varName;        /* Name of a variable in interp. */
  985.     char *newValue;        /* New value for varName. */
  986.     int flags;            /* Various flags that tell how to set value:
  987.                  * any of TCL_GLOBAL_ONLY,
  988.                  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  989.                  * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */
  990. {
  991.     return Tcl_SetVar2(interp, varName, (char *) NULL, newValue,
  992.                (flags | TCL_PARSE_PART1));
  993. }
  994.  
  995. /*
  996.  *----------------------------------------------------------------------
  997.  *
  998.  * Tcl_SetVar2 --
  999.  *
  1000.  *      Given a two-part variable name, which may refer either to a
  1001.  *      scalar variable or an element of an array, change the value
  1002.  *      of the variable.  If the named scalar or array or element
  1003.  *      doesn't exist then create one.
  1004.  *
  1005.  * Results:
  1006.  *    Returns a pointer to the malloc'ed string which is the character
  1007.  *    representation of the variable's new value. The caller must not
  1008.  *    modify this string. If the write operation was disallowed because an
  1009.  *    array was expected but not found (or vice versa), then NULL is
  1010.  *    returned; if the TCL_LEAVE_ERR_MSG flag is set, then an explanatory
  1011.  *    message will be left in interp->result. Note that the returned
  1012.  *    string may not be the same as newValue; this is because variable
  1013.  *    traces may modify the variable's value.
  1014.  *
  1015.  * Side effects:
  1016.  *      The value of the given variable is set. If either the array
  1017.  *      or the entry didn't exist then a new one is created.
  1018.  *
  1019.  *----------------------------------------------------------------------
  1020.  */
  1021.  
  1022. char *
  1023. Tcl_SetVar2(interp, part1, part2, newValue, flags)
  1024.     Tcl_Interp *interp;         /* Command interpreter in which variable is
  1025.                                  * to be looked up. */
  1026.     char *part1;                /* If part2 is NULL, this is name of scalar
  1027.                                  * variable. Otherwise it is the name of
  1028.                                  * an array. */
  1029.     char *part2;                /* Name of an element within an array, or
  1030.                  * NULL. */
  1031.     char *newValue;             /* New value for variable. */
  1032.     int flags;                  /* Various flags that tell how to set value:
  1033.                  * any of TCL_GLOBAL_ONLY,
  1034.                  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1035.                  * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG, or 
  1036.                  * TCL_PARSE_PART1. */
  1037. {
  1038.     register Tcl_Obj *valuePtr;
  1039.     register Tcl_Obj *part1Ptr;
  1040.     register Tcl_Obj *part2Ptr = NULL;
  1041.     Tcl_Obj *varValuePtr;
  1042.     int length;
  1043.  
  1044.     /*
  1045.      * Create an object holding the variable's new value and use
  1046.      * Tcl_ObjSetVar2 to actually set the variable.
  1047.      */
  1048.  
  1049.     length = newValue ? strlen(newValue) : 0;
  1050.     TclNewObj(valuePtr);
  1051.     TclInitStringRep(valuePtr, newValue, length);
  1052.     Tcl_IncrRefCount(valuePtr);
  1053.  
  1054.     length = strlen(part1) ;
  1055.     TclNewObj(part1Ptr);
  1056.     TclInitStringRep(part1Ptr, part1, length);
  1057.     Tcl_IncrRefCount(part1Ptr);
  1058.  
  1059.     if (part2 != NULL) {
  1060.         length = strlen(part2);
  1061.         TclNewObj(part2Ptr);
  1062.         TclInitStringRep(part2Ptr, part2, length);
  1063.     Tcl_IncrRefCount(part2Ptr);
  1064.     }
  1065.     
  1066.     varValuePtr = Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, valuePtr,
  1067.         flags);
  1068.     
  1069.     TclDecrRefCount(part1Ptr);      /* done with the part1 name object */
  1070.     if (part2Ptr != NULL) {
  1071.     TclDecrRefCount(part2Ptr);  /* and the part2 name object */
  1072.     }
  1073.     Tcl_DecrRefCount(valuePtr); /* done with the object */
  1074.     
  1075.     if (varValuePtr == NULL) {
  1076.     /*
  1077.      * Move the interpreter's object result to the string result, 
  1078.      * then reset the object result.
  1079.      * FAILS IF OBJECT RESULT'S STRING REPRESENTATION CONTAINS NULLS.
  1080.      */
  1081.  
  1082.     Tcl_SetResult(interp,
  1083.             TclGetStringFromObj(Tcl_GetObjResult(interp), (int *) NULL),
  1084.             TCL_VOLATILE);
  1085.     return NULL;
  1086.     }
  1087.  
  1088.     /*
  1089.      * THIS FAILS IF Tcl_ObjSetVar2's RESULT'S STRING REP HAS A NULL BYTE.
  1090.      */
  1091.  
  1092.     return TclGetStringFromObj(varValuePtr, (int *) NULL);
  1093. }
  1094.  
  1095. /*
  1096.  *----------------------------------------------------------------------
  1097.  *
  1098.  * Tcl_ObjSetVar2 --
  1099.  *
  1100.  *    Given a two-part variable name, which may refer either to a scalar
  1101.  *    variable or an element of an array, change the value of the variable
  1102.  *    to a new Tcl object value. If the named scalar or array or element
  1103.  *    doesn't exist then create one.
  1104.  *
  1105.  * Results:
  1106.  *    Returns a pointer to the Tcl_Obj holding the new value of the
  1107.  *    variable. If the write operation was disallowed because an array was
  1108.  *    expected but not found (or vice versa), then NULL is returned; if
  1109.  *    the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will
  1110.  *    be left in the interpreter's result. Note that the returned object
  1111.  *    may not be the same one referenced by newValuePtr; this is because
  1112.  *    variable traces may modify the variable's value.
  1113.  *
  1114.  * Side effects:
  1115.  *    The value of the given variable is set. If either the array or the
  1116.  *    entry didn't exist then a new variable is created.
  1117.  *
  1118.  *    The reference count is decremented for any old value of the variable
  1119.  *    and incremented for its new value. If the new value for the variable
  1120.  *    is not the same one referenced by newValuePtr (perhaps as a result
  1121.  *    of a variable trace), then newValuePtr's ref count is left unchanged
  1122.  *    by Tcl_ObjSetVar2. newValuePtr's ref count is also left unchanged if
  1123.  *    we are appending it as a string value: that is, if "flags" includes
  1124.  *    TCL_APPEND_VALUE but not TCL_LIST_ELEMENT.
  1125.  *
  1126.  *    The reference count for the returned object is _not_ incremented: if
  1127.  *    you want to keep a reference to the object you must increment its
  1128.  *    ref count yourself.
  1129.  *
  1130.  *----------------------------------------------------------------------
  1131.  */
  1132.  
  1133. Tcl_Obj *
  1134. Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, newValuePtr, flags)
  1135.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  1136.                  * to be found. */
  1137.     register Tcl_Obj *part1Ptr;    /* Points to an object holding the name of
  1138.                  * an array (if part2 is non-NULL) or the
  1139.                  * name of a variable. */
  1140.     register Tcl_Obj *part2Ptr;    /* If non-null, points to an object holding
  1141.                  * the name of an element in the array
  1142.                  * part1Ptr. */
  1143.     Tcl_Obj *newValuePtr;    /* New value for variable. */
  1144.     int flags;            /* Various flags that tell how to set value:
  1145.                  * any of TCL_GLOBAL_ONLY,
  1146.                  * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE,
  1147.                  * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG, or
  1148.                  * TCL_PARSE_PART1. */
  1149. {
  1150.     Interp *iPtr = (Interp *) interp;
  1151.     register Var *varPtr;
  1152.     Var *arrayPtr;
  1153.     Tcl_Obj *oldValuePtr;
  1154.     Tcl_Obj *resultPtr = NULL;
  1155.     char *part1, *bytes;
  1156.     char *part2 = NULL;
  1157.     int length, result;
  1158.  
  1159.     /*
  1160.      * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
  1161.      */
  1162.  
  1163.     part1 = TclGetStringFromObj(part1Ptr, (int *) NULL);
  1164.     if (part2Ptr != NULL) {
  1165.     part2 = TclGetStringFromObj(part2Ptr, (int *) NULL);
  1166.     }
  1167.     
  1168.     varPtr = TclLookupVar(interp, part1, part2, flags, "set",
  1169.         /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
  1170.     if (varPtr == NULL) {
  1171.     return NULL;
  1172.     }
  1173.  
  1174.     /*
  1175.      * If the variable is in a hashtable and its hPtr field is NULL, then we
  1176.      * have an upvar to an array element where the array was deleted,
  1177.      * leaving the element dangling at the end of the upvar. Generate an
  1178.      * error (allowing the variable to be reset would screw up our storage
  1179.      * allocation and is meaningless anyway).
  1180.      */
  1181.  
  1182.     if ((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) {
  1183.     if (flags & TCL_LEAVE_ERR_MSG) {
  1184.         VarErrMsg(interp, part1, part2, "set", danglingUpvar);
  1185.     }
  1186.     return NULL;
  1187.     }
  1188.  
  1189.     /*
  1190.      * It's an error to try to set an array variable itself.
  1191.      */
  1192.  
  1193.     if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
  1194.     if (flags & TCL_LEAVE_ERR_MSG) {
  1195.         VarErrMsg(interp, part1, part2, "set", isArray);
  1196.     }
  1197.     return NULL;
  1198.     }
  1199.  
  1200.     /*
  1201.      * At this point, if we were appending, we used to call read traces: we
  1202.      * treated append as a read-modify-write. However, it seemed unlikely to
  1203.      * us that a real program would be interested in such reads being done
  1204.      * during a set operation.
  1205.      */
  1206.  
  1207.     /*
  1208.      * Set the variable's new value. If appending, append the new value to
  1209.      * the variable, either as a list element or as a string. Also, if
  1210.      * appending, then if the variable's old value is unshared we can modify
  1211.      * it directly, otherwise we must create a new copy to modify: this is
  1212.      * "copy on write".
  1213.      */
  1214.  
  1215.     oldValuePtr = varPtr->value.objPtr;
  1216.     if (flags & TCL_APPEND_VALUE) {
  1217.     if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) {
  1218.         Tcl_DecrRefCount(oldValuePtr);     /* discard old value */
  1219.         varPtr->value.objPtr = NULL;
  1220.         oldValuePtr = NULL;
  1221.     }
  1222.     if (flags & TCL_LIST_ELEMENT) {           /* append list element */
  1223.         if (oldValuePtr == NULL) {
  1224.         TclNewObj(oldValuePtr);
  1225.         varPtr->value.objPtr = oldValuePtr;
  1226.         Tcl_IncrRefCount(oldValuePtr); /* since var is reference */
  1227.         } else if (Tcl_IsShared(oldValuePtr)) {
  1228.         varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr);
  1229.         Tcl_DecrRefCount(oldValuePtr);
  1230.         oldValuePtr = varPtr->value.objPtr;
  1231.         Tcl_IncrRefCount(oldValuePtr); /* since var is reference */
  1232.         }
  1233.         result = Tcl_ListObjAppendElement(interp, oldValuePtr,
  1234.             newValuePtr);
  1235.         if (result != TCL_OK) {
  1236.         return NULL;
  1237.         }
  1238.     } else {                       /* append string */
  1239.         /*
  1240.          * We append newValuePtr's bytes but don't change its ref count.
  1241.          */
  1242.  
  1243.         bytes = Tcl_GetStringFromObj(newValuePtr, &length);
  1244.         if (oldValuePtr == NULL) {
  1245.         varPtr->value.objPtr = Tcl_NewStringObj(bytes, length);
  1246.         Tcl_IncrRefCount(varPtr->value.objPtr);
  1247.         } else {
  1248.         if (Tcl_IsShared(oldValuePtr)) {   /* append to copy */
  1249.             varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr);
  1250.             TclDecrRefCount(oldValuePtr);
  1251.             oldValuePtr = varPtr->value.objPtr;
  1252.             Tcl_IncrRefCount(oldValuePtr); /* since var is ref */
  1253.         }
  1254.         Tcl_AppendToObj(oldValuePtr, bytes, length);
  1255.         }
  1256.     }
  1257.     } else {
  1258.     if (flags & TCL_LIST_ELEMENT) {           /* set var to list element */
  1259.         int neededBytes, listFlags;
  1260.  
  1261.         /*
  1262.          * We set the variable to the result of converting newValuePtr's
  1263.          * string rep to a list element. We do not change newValuePtr's
  1264.          * ref count.
  1265.          */
  1266.  
  1267.         if (oldValuePtr != NULL) {
  1268.         Tcl_DecrRefCount(oldValuePtr); /* discard old value */
  1269.         }
  1270.         bytes = Tcl_GetStringFromObj(newValuePtr, &length);
  1271.         neededBytes = Tcl_ScanElement(bytes, &listFlags);
  1272.         oldValuePtr = Tcl_NewObj();
  1273.         oldValuePtr->bytes = (char *)
  1274.             ckalloc((unsigned) (neededBytes + 1));
  1275.         oldValuePtr->length = Tcl_ConvertElement(bytes,
  1276.             oldValuePtr->bytes, listFlags);
  1277.         varPtr->value.objPtr = oldValuePtr;
  1278.         Tcl_IncrRefCount(varPtr->value.objPtr);
  1279.     } else if (newValuePtr != oldValuePtr) {
  1280.         varPtr->value.objPtr = newValuePtr;
  1281.         Tcl_IncrRefCount(newValuePtr);      /* var is another ref */
  1282.         if (oldValuePtr != NULL) {
  1283.         TclDecrRefCount(oldValuePtr);   /* discard old value */
  1284.         }
  1285.     }
  1286.     }
  1287.     TclSetVarScalar(varPtr);
  1288.     TclClearVarUndefined(varPtr);
  1289.     if (arrayPtr != NULL) {
  1290.     TclClearVarUndefined(arrayPtr);
  1291.     }
  1292.  
  1293.     /*
  1294.      * Invoke any write traces for the variable.
  1295.      */
  1296.  
  1297.     if ((varPtr->tracePtr != NULL)
  1298.         || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  1299.     char *msg = CallTraces(iPtr, arrayPtr, varPtr, part1, part2,
  1300.             (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1)) | TCL_TRACE_WRITES);
  1301.     if (msg != NULL) {
  1302.         if (flags & TCL_LEAVE_ERR_MSG) {
  1303.         VarErrMsg(interp, part1, part2, "set", msg);
  1304.         }
  1305.         goto cleanup;
  1306.     }
  1307.     }
  1308.  
  1309.     /*
  1310.      * Return the variable's value unless the variable was changed in some
  1311.      * gross way by a trace (e.g. it was unset and then recreated as an
  1312.      * array). 
  1313.      */
  1314.  
  1315.     if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
  1316.     return varPtr->value.objPtr;
  1317.     }
  1318.  
  1319.     /*
  1320.      * A trace changed the value in some gross way. Return an empty string
  1321.      * object.
  1322.      */
  1323.     
  1324.     resultPtr = iPtr->emptyObjPtr;
  1325.  
  1326.     /*
  1327.      * If the variable doesn't exist anymore and no-one's using it, then
  1328.      * free up the relevant structures and hash table entries.
  1329.      */
  1330.  
  1331.     cleanup:
  1332.     if (TclIsVarUndefined(varPtr)) {
  1333.     CleanupVar(varPtr, arrayPtr);
  1334.     }
  1335.     return resultPtr;
  1336. }
  1337.  
  1338. /*
  1339.  *----------------------------------------------------------------------
  1340.  *
  1341.  * TclSetIndexedScalar --
  1342.  *
  1343.  *    Change the Tcl object value of a local scalar variable in the active
  1344.  *    procedure, given its compile-time allocated index in the procedure's
  1345.  *    array of local variables.
  1346.  *
  1347.  * Results:
  1348.  *    Returns a pointer to the Tcl_Obj holding the new value of the
  1349.  *    variable given by localIndex. If the specified variable doesn't
  1350.  *    exist, or there is a clash in array usage, or an error occurs while
  1351.  *    executing variable traces, then NULL is returned and a message will
  1352.  *    be left in the interpreter's result if leaveErrorMsg is 1. Note
  1353.  *    that the returned object may not be the same one referenced by
  1354.  *    newValuePtr; this is because variable traces may modify the
  1355.  *    variable's value.
  1356.  *
  1357.  * Side effects:
  1358.  *    The value of the given variable is set. The reference count is
  1359.  *    decremented for any old value of the variable and incremented for
  1360.  *    its new value. If as a result of a variable trace the new value for
  1361.  *    the variable is not the same one referenced by newValuePtr, then
  1362.  *    newValuePtr's ref count is left unchanged. The ref count for the
  1363.  *    returned object is _not_ incremented to reflect the returned
  1364.  *    reference; if you want to keep a reference to the object you must
  1365.  *    increment its ref count yourself. This procedure does not create
  1366.  *    new variables, but only sets those recognized at compile time.
  1367.  *
  1368.  *----------------------------------------------------------------------
  1369.  */
  1370.  
  1371. Tcl_Obj *
  1372. TclSetIndexedScalar(interp, localIndex, newValuePtr, leaveErrorMsg)
  1373.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  1374.                  * to be found. */
  1375.     int localIndex;        /* Index of variable in procedure's array
  1376.                  * of local variables. */
  1377.     Tcl_Obj *newValuePtr;    /* New value for variable. */
  1378.     int leaveErrorMsg;        /* 1 if to leave an error message in
  1379.                  * the interpreter's result on an error.
  1380.                  * Otherwise no error message is left. */
  1381. {
  1382.     Interp *iPtr = (Interp *) interp;
  1383.     CallFrame *varFramePtr = iPtr->varFramePtr;
  1384.                 /* Points to the procedure call frame whose
  1385.                  * variables are currently in use. Same as
  1386.                  * the current procedure's frame, if any,
  1387.                  * unless an "uplevel" is executing. */
  1388.     Var *compiledLocals = varFramePtr->compiledLocals;
  1389.     register Var *varPtr;    /* Points to the variable's in-frame Var
  1390.                  * structure. */
  1391.     char *varName;        /* Name of the local variable. */
  1392.     Tcl_Obj *oldValuePtr;
  1393.     Tcl_Obj *resultPtr = NULL;
  1394.  
  1395. #ifdef TCL_COMPILE_DEBUG
  1396.     Proc *procPtr = varFramePtr->procPtr;
  1397.     int localCt = procPtr->numCompiledLocals;
  1398.  
  1399.     if (compiledLocals == NULL) {
  1400.     fprintf(stderr, "\nTclSetIndexedScalar: can't set local %i in frame 0x%x, no compiled locals\n",
  1401.             localIndex, (unsigned int) varFramePtr);
  1402.     panic("TclSetIndexedScalar: no compiled locals in frame 0x%x",
  1403.           (unsigned int) varFramePtr);
  1404.     }
  1405.     if ((localIndex < 0) || (localIndex >= localCt)) {
  1406.     fprintf(stderr, "\nTclSetIndexedScalar: can't set local %i in frame 0x%x with %i locals\n",
  1407.             localIndex, (unsigned int) varFramePtr, localCt);
  1408.     panic("TclSetIndexedScalar: bad local index %i in frame 0x%x",
  1409.           localIndex, (unsigned int) varFramePtr);
  1410.     }
  1411. #endif /* TCL_COMPILE_DEBUG */
  1412.     
  1413.     varPtr = &(compiledLocals[localIndex]);
  1414.     varName = varPtr->name;
  1415.  
  1416.     /*
  1417.      * If varPtr is a link variable, we have a reference to some variable
  1418.      * that was created through an "upvar" or "global" command, or we have a
  1419.      * reference to a variable in an enclosing namespace. Traverse through
  1420.      * any links until we find the referenced variable.
  1421.      */
  1422.     
  1423.     while (TclIsVarLink(varPtr)) {
  1424.     varPtr = varPtr->value.linkPtr;
  1425.     }
  1426.  
  1427.     /*
  1428.      * If the variable is in a hashtable and its hPtr field is NULL, then we
  1429.      * have an upvar to an array element where the array was deleted,
  1430.      * leaving the element dangling at the end of the upvar. Generate an
  1431.      * error (allowing the variable to be reset would screw up our storage
  1432.      * allocation and is meaningless anyway).
  1433.      */
  1434.  
  1435.     if ((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) {
  1436.     if (leaveErrorMsg) {
  1437.         VarErrMsg(interp, varName, NULL, "set", danglingUpvar);
  1438.     }
  1439.     return NULL;
  1440.     }
  1441.  
  1442.     /*
  1443.      * It's an error to try to set an array variable itself.
  1444.      */
  1445.  
  1446.     if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
  1447.     if (leaveErrorMsg) {
  1448.         VarErrMsg(interp, varName, NULL, "set", isArray);
  1449.     }
  1450.     return NULL;
  1451.     }
  1452.  
  1453.     /*
  1454.      * Set the variable's new value and discard its old value. We don't
  1455.      * append with this "set" procedure so the old value isn't needed.
  1456.      */
  1457.  
  1458.     oldValuePtr = varPtr->value.objPtr;
  1459.     if (newValuePtr != oldValuePtr) {        /* set new value */
  1460.     varPtr->value.objPtr = newValuePtr;
  1461.     Tcl_IncrRefCount(newValuePtr);       /* var is another ref to obj */
  1462.     if (oldValuePtr != NULL) {
  1463.         TclDecrRefCount(oldValuePtr);    /* discard old value */
  1464.     }
  1465.     }
  1466.     TclSetVarScalar(varPtr);
  1467.     TclClearVarUndefined(varPtr);
  1468.  
  1469.     /*
  1470.      * Invoke any write traces for the variable.
  1471.      */
  1472.  
  1473.     if (varPtr->tracePtr != NULL) {
  1474.     char *msg = CallTraces(iPtr, /*arrayPtr*/ NULL, varPtr,
  1475.             varName, (char *) NULL, TCL_TRACE_WRITES);
  1476.     if (msg != NULL) {
  1477.         if (leaveErrorMsg) {
  1478.         VarErrMsg(interp, varName, NULL, "set", msg);
  1479.         }
  1480.         goto cleanup;
  1481.     }
  1482.     }
  1483.  
  1484.     /*
  1485.      * Return the variable's value unless the variable was changed in some
  1486.      * gross way by a trace (e.g. it was unset and then recreated as an
  1487.      * array). If it was changed is a gross way, just return an empty string
  1488.      * object.
  1489.      */
  1490.  
  1491.     if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
  1492.     return varPtr->value.objPtr;
  1493.     }
  1494.     
  1495.     resultPtr = Tcl_NewObj();
  1496.  
  1497.     /*
  1498.      * If the variable doesn't exist anymore and no-one's using it, then
  1499.      * free up the relevant structures and hash table entries.
  1500.      */
  1501.  
  1502.     cleanup:
  1503.     if (TclIsVarUndefined(varPtr)) {
  1504.     CleanupVar(varPtr, NULL);
  1505.     }
  1506.     return resultPtr;
  1507. }
  1508.  
  1509. /*
  1510.  *----------------------------------------------------------------------
  1511.  *
  1512.  * TclSetElementOfIndexedArray --
  1513.  *
  1514.  *    Change the Tcl object value of an element in a local array
  1515.  *    variable. The element is named by the object elemPtr while the array
  1516.  *    is specified by its index in the active procedure's array of
  1517.  *    compiler allocated local variables.
  1518.  *
  1519.  * Results:
  1520.  *    Returns a pointer to the Tcl_Obj holding the new value of the
  1521.  *    element. If the specified array or element doesn't exist, or there
  1522.  *    is a clash in array usage, or an error occurs while executing
  1523.  *    variable traces, then NULL is returned and a message will be left in
  1524.  *    the interpreter's result if leaveErrorMsg is 1. Note that the
  1525.  *    returned object may not be the same one referenced by newValuePtr;
  1526.  *    this is because variable traces may modify the variable's value.
  1527.  *
  1528.  * Side effects:
  1529.  *    The value of the given array element is set. The reference count is
  1530.  *    decremented for any old value of the element and incremented for its
  1531.  *    new value. If as a result of a variable trace the new value for the
  1532.  *    element is not the same one referenced by newValuePtr, then
  1533.  *    newValuePtr's ref count is left unchanged. The ref count for the
  1534.  *    returned object is _not_ incremented to reflect the returned
  1535.  *    reference; if you want to keep a reference to the object you must
  1536.  *    increment its ref count yourself. This procedure will not create new
  1537.  *    array variables, but only sets elements of those arrays recognized
  1538.  *    at compile time. However, if the entry doesn't exist then a new
  1539.  *    variable is created.
  1540.  *
  1541.  *----------------------------------------------------------------------
  1542.  */
  1543.  
  1544. Tcl_Obj *
  1545. TclSetElementOfIndexedArray(interp, localIndex, elemPtr, newValuePtr,
  1546.         leaveErrorMsg)
  1547.     Tcl_Interp *interp;        /* Command interpreter in which the array is
  1548.                  * to be found. */
  1549.     int localIndex;        /* Index of array variable in procedure's
  1550.                  * array of local variables. */
  1551.     Tcl_Obj *elemPtr;        /* Points to an object holding the name of
  1552.                  * an element to set in the array. */
  1553.     Tcl_Obj *newValuePtr;    /* New value for variable. */
  1554.     int leaveErrorMsg;        /* 1 if to leave an error message in
  1555.                  * the interpreter's result on an error.
  1556.                  * Otherwise no error message is left. */
  1557. {
  1558.     Interp *iPtr = (Interp *) interp;
  1559.     CallFrame *varFramePtr = iPtr->varFramePtr;
  1560.                 /* Points to the procedure call frame whose
  1561.                  * variables are currently in use. Same as
  1562.                  * the current procedure's frame, if any,
  1563.                  * unless an "uplevel" is executing. */
  1564.     Var *compiledLocals = varFramePtr->compiledLocals;
  1565.     Var *arrayPtr;        /* Points to the array's in-frame Var
  1566.                  * structure. */
  1567.     char *arrayName;        /* Name of the local array. */
  1568.     char *elem;
  1569.     Tcl_HashEntry *hPtr;
  1570.     Var *varPtr = NULL;        /* Points to the element's Var structure
  1571.                  * that we return. */
  1572.     Tcl_Obj *resultPtr = NULL;
  1573.     Tcl_Obj *oldValuePtr;
  1574.     int new;
  1575.     
  1576. #ifdef TCL_COMPILE_DEBUG
  1577.     Proc *procPtr = varFramePtr->procPtr;
  1578.     int localCt = procPtr->numCompiledLocals;
  1579.  
  1580.     if (compiledLocals == NULL) {
  1581.     fprintf(stderr, "\nTclSetElementOfIndexedArray: can't set element of local %i in frame 0x%x, no compiled locals\n",
  1582.             localIndex, (unsigned int) varFramePtr);
  1583.     panic("TclSetIndexedScalar: no compiled locals in frame 0x%x",
  1584.           (unsigned int) varFramePtr);
  1585.     }
  1586.     if ((localIndex < 0) || (localIndex >= localCt)) {
  1587.     fprintf(stderr, "\nTclSetIndexedScalar: can't set elememt of local %i in frame 0x%x with %i locals\n",
  1588.             localIndex, (unsigned int) varFramePtr, localCt);
  1589.     panic("TclSetElementOfIndexedArray: bad local index %i in frame 0x%x",
  1590.           localIndex, (unsigned int) varFramePtr);
  1591.     }
  1592. #endif /* TCL_COMPILE_DEBUG */
  1593.  
  1594.     /*
  1595.      * THIS FAILS IF THE ELEMENT NAME OBJECT'S STRING REP HAS A NULL BYTE.
  1596.      */
  1597.     
  1598.     elem = Tcl_GetStringFromObj(elemPtr, (int *) NULL);
  1599.     arrayPtr = &(compiledLocals[localIndex]);
  1600.     arrayName = arrayPtr->name;
  1601.  
  1602.     /*
  1603.      * If arrayPtr is a link variable, we have a reference to some variable
  1604.      * that was created through an "upvar" or "global" command, or we have a
  1605.      * reference to a variable in an enclosing namespace. Traverse through
  1606.      * any links until we find the referenced variable.
  1607.      */
  1608.     
  1609.     while (TclIsVarLink(arrayPtr)) {
  1610.     arrayPtr = arrayPtr->value.linkPtr;
  1611.     }
  1612.  
  1613.     /*
  1614.      * Make sure we're dealing with an array.
  1615.      */
  1616.  
  1617.     if (TclIsVarUndefined(arrayPtr) && !TclIsVarArrayElement(arrayPtr)) {
  1618.     TclSetVarArray(arrayPtr);
  1619.     arrayPtr->value.tablePtr =
  1620.             (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  1621.     Tcl_InitHashTable(arrayPtr->value.tablePtr, TCL_STRING_KEYS);
  1622.     TclClearVarUndefined(arrayPtr);
  1623.     } else if (!TclIsVarArray(arrayPtr)) {
  1624.     if (leaveErrorMsg) {
  1625.         VarErrMsg(interp, arrayName, elem, "set", needArray);
  1626.     }
  1627.     goto errorReturn;
  1628.     } 
  1629.  
  1630.     /*
  1631.      * Look up the element.
  1632.      */
  1633.  
  1634.     hPtr = Tcl_CreateHashEntry(arrayPtr->value.tablePtr, elem, &new);
  1635.     if (new) {
  1636.     if (arrayPtr->searchPtr != NULL) {
  1637.         DeleteSearches(arrayPtr);
  1638.     }
  1639.     varPtr = NewVar();
  1640.     Tcl_SetHashValue(hPtr, varPtr);
  1641.     varPtr->hPtr = hPtr;
  1642.         varPtr->nsPtr = varFramePtr->nsPtr;
  1643.     TclSetVarArrayElement(varPtr);
  1644.     }
  1645.     varPtr = (Var *) Tcl_GetHashValue(hPtr);
  1646.  
  1647.     /*
  1648.      * It's an error to try to set an array variable itself.
  1649.      */
  1650.  
  1651.     if (TclIsVarArray(varPtr)) {
  1652.     if (leaveErrorMsg) {
  1653.         VarErrMsg(interp, arrayName, elem, "set", isArray);
  1654.     }
  1655.     goto errorReturn;
  1656.     }
  1657.  
  1658.     /*
  1659.      * Set the variable's new value and discard the old one. We don't
  1660.      * append with this "set" procedure so the old value isn't needed.
  1661.      */
  1662.  
  1663.     oldValuePtr = varPtr->value.objPtr;
  1664.     if (newValuePtr != oldValuePtr) {         /* set new value */
  1665.     varPtr->value.objPtr = newValuePtr;
  1666.     Tcl_IncrRefCount(newValuePtr);       /* var is another ref to obj */
  1667.     if (oldValuePtr != NULL) {
  1668.         TclDecrRefCount(oldValuePtr);    /* discard old value */
  1669.     }
  1670.     }
  1671.     TclSetVarScalar(varPtr);
  1672.     TclClearVarUndefined(varPtr);
  1673.  
  1674.     /*
  1675.      * Invoke any write traces for the element variable.
  1676.      */
  1677.  
  1678.     if ((varPtr->tracePtr != NULL)
  1679.         || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  1680.     char *msg = CallTraces(iPtr, arrayPtr, varPtr, arrayName, elem,
  1681.         TCL_TRACE_WRITES);
  1682.     if (msg != NULL) {
  1683.         if (leaveErrorMsg) {
  1684.         VarErrMsg(interp, arrayName, elem, "set", msg);
  1685.         }
  1686.         goto errorReturn;
  1687.     }
  1688.     }
  1689.  
  1690.     /*
  1691.      * Return the element's value unless it was changed in some gross way by
  1692.      * a trace (e.g. it was unset and then recreated as an array). If it was
  1693.      * changed is a gross way, just return an empty string object.
  1694.      */
  1695.  
  1696.     if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) {
  1697.     return varPtr->value.objPtr;
  1698.     }
  1699.     
  1700.     resultPtr = Tcl_NewObj();
  1701.  
  1702.     /*
  1703.      * An error. If the variable doesn't exist anymore and no-one's using
  1704.      * it, then free up the relevant structures and hash table entries.
  1705.      */
  1706.  
  1707.     errorReturn:
  1708.     if (varPtr != NULL) {
  1709.     if (TclIsVarUndefined(varPtr)) {
  1710.         CleanupVar(varPtr, NULL); /* note: array isn't in hashtable */
  1711.     }
  1712.     }
  1713.     return resultPtr;
  1714. }
  1715.  
  1716. /*
  1717.  *----------------------------------------------------------------------
  1718.  *
  1719.  * TclIncrVar2 --
  1720.  *
  1721.  *    Given a two-part variable name, which may refer either to a scalar
  1722.  *    variable or an element of an array, increment the Tcl object value
  1723.  *    of the variable by a specified amount.
  1724.  *
  1725.  * Results:
  1726.  *    Returns a pointer to the Tcl_Obj holding the new value of the
  1727.  *    variable. If the specified variable doesn't exist, or there is a
  1728.  *    clash in array usage, or an error occurs while executing variable
  1729.  *    traces, then NULL is returned and a message will be left in
  1730.  *    the interpreter's result.
  1731.  *
  1732.  * Side effects:
  1733.  *    The value of the given variable is incremented by the specified
  1734.  *    amount. If either the array or the entry didn't exist then a new
  1735.  *    variable is created. The ref count for the returned object is _not_
  1736.  *    incremented to reflect the returned reference; if you want to keep a
  1737.  *    reference to the object you must increment its ref count yourself.
  1738.  *
  1739.  *----------------------------------------------------------------------
  1740.  */
  1741.  
  1742. Tcl_Obj *
  1743. TclIncrVar2(interp, part1Ptr, part2Ptr, incrAmount, part1NotParsed)
  1744.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  1745.                  * to be found. */
  1746.     Tcl_Obj *part1Ptr;        /* Points to an object holding the name of
  1747.                  * an array (if part2 is non-NULL) or the
  1748.                  * name of a variable. */
  1749.     Tcl_Obj *part2Ptr;        /* If non-null, points to an object holding
  1750.                  * the name of an element in the array
  1751.                  * part1Ptr. */
  1752.     long incrAmount;        /* Amount to be added to variable. */
  1753.     int part1NotParsed;        /* 1 if part1 hasn't yet been parsed into
  1754.                  * an array name and index (if any). */
  1755. {
  1756.     register Tcl_Obj *varValuePtr;
  1757.     Tcl_Obj *resultPtr;
  1758.     int createdNewObj;        /* Set 1 if var's value object is shared
  1759.                  * so we must increment a copy (i.e. copy
  1760.                  * on write). */
  1761.     long i;
  1762.     int flags, result;
  1763.  
  1764.     flags = TCL_LEAVE_ERR_MSG;
  1765.     if (part1NotParsed) {
  1766.     flags |= TCL_PARSE_PART1;
  1767.     }
  1768.     
  1769.     varValuePtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);
  1770.     if (varValuePtr == NULL) {
  1771.     Tcl_AddObjErrorInfo(interp,
  1772.         "\n    (reading value of variable to increment)", -1);
  1773.     return NULL;
  1774.     }
  1775.  
  1776.     /*
  1777.      * Increment the variable's value. If the object is unshared we can
  1778.      * modify it directly, otherwise we must create a new copy to modify:
  1779.      * this is "copy on write". Then free the variable's old string
  1780.      * representation, if any, since it will no longer be valid.
  1781.      */
  1782.  
  1783.     createdNewObj = 0;
  1784.     if (Tcl_IsShared(varValuePtr)) {
  1785.     varValuePtr = Tcl_DuplicateObj(varValuePtr);
  1786.     createdNewObj = 1;
  1787.     }
  1788.     result = Tcl_GetLongFromObj(interp, varValuePtr, &i);
  1789.     if (result != TCL_OK) {
  1790.     if (createdNewObj) {
  1791.         Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */
  1792.     }
  1793.     return NULL;
  1794.     }
  1795.     Tcl_SetLongObj(varValuePtr, (i + incrAmount));
  1796.  
  1797.     /*
  1798.      * Store the variable's new value and run any write traces.
  1799.      */
  1800.     
  1801.     resultPtr = Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, varValuePtr,
  1802.         flags);
  1803.     if (resultPtr == NULL) {
  1804.     return NULL;
  1805.     }
  1806.     return resultPtr;
  1807. }
  1808.  
  1809. /*
  1810.  *----------------------------------------------------------------------
  1811.  *
  1812.  * TclIncrIndexedScalar --
  1813.  *
  1814.  *    Increments the Tcl object value of a local scalar variable in the
  1815.  *    active procedure, given its compile-time allocated index in the
  1816.  *    procedure's array of local variables.
  1817.  *
  1818.  * Results:
  1819.  *    Returns a pointer to the Tcl_Obj holding the new value of the
  1820.  *    variable given by localIndex. If the specified variable doesn't
  1821.  *    exist, or there is a clash in array usage, or an error occurs while
  1822.  *    executing variable traces, then NULL is returned and a message will
  1823.  *    be left in the interpreter's result. 
  1824.  *
  1825.  * Side effects:
  1826.  *    The value of the given variable is incremented by the specified
  1827.  *    amount. The ref count for the returned object is _not_ incremented
  1828.  *    to reflect the returned reference; if you want to keep a reference
  1829.  *    to the object you must increment its ref count yourself.
  1830.  *
  1831.  *----------------------------------------------------------------------
  1832.  */
  1833.  
  1834. Tcl_Obj *
  1835. TclIncrIndexedScalar(interp, localIndex, incrAmount)
  1836.     Tcl_Interp *interp;        /* Command interpreter in which variable is
  1837.                  * to be found. */
  1838.     int localIndex;        /* Index of variable in procedure's array
  1839.                  * of local variables. */
  1840.     long incrAmount;        /* Amount to be added to variable. */
  1841. {
  1842.     register Tcl_Obj *varValuePtr;
  1843.     Tcl_Obj *resultPtr;
  1844.     int createdNewObj;        /* Set 1 if var's value object is shared
  1845.                  * so we must increment a copy (i.e. copy
  1846.                  * on write). */
  1847.     long i;
  1848.     int result;
  1849.  
  1850.     varValuePtr = TclGetIndexedScalar(interp, localIndex,
  1851.                                       /*leaveErrorMsg*/ 1);
  1852.     if (varValuePtr == NULL) {
  1853.     Tcl_AddObjErrorInfo(interp,
  1854.         "\n    (reading value of variable to increment)", -1);
  1855.     return NULL;
  1856.     }
  1857.  
  1858.     /*
  1859.      * Reach into the object's representation to extract and increment the
  1860.      * variable's value. If the object is unshared we can modify it
  1861.      * directly, otherwise we must create a new copy to modify: this is
  1862.      * "copy on write". Then free the variable's old string representation,
  1863.      * if any, since it will no longer be valid.
  1864.      */
  1865.  
  1866.     createdNewObj = 0;
  1867.     if (Tcl_IsShared(varValuePtr)) {
  1868.     createdNewObj = 1;
  1869.     varValuePtr = Tcl_DuplicateObj(varValuePtr);
  1870.     }
  1871.     result = Tcl_GetLongFromObj(interp, varValuePtr, &i);
  1872.     if (result != TCL_OK) {
  1873.     if (createdNewObj) {
  1874.         Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */
  1875.     }
  1876.     return NULL;
  1877.     }
  1878.     Tcl_SetLongObj(varValuePtr, (i + incrAmount));
  1879.  
  1880.     /*
  1881.      * Store the variable's new value and run any write traces.
  1882.      */
  1883.     
  1884.     resultPtr = TclSetIndexedScalar(interp, localIndex, varValuePtr,
  1885.                     /*leaveErrorMsg*/ 1);
  1886.     if (resultPtr == NULL) {
  1887.     return NULL;
  1888.     }
  1889.     return resultPtr;
  1890. }
  1891.  
  1892. /*
  1893.  *----------------------------------------------------------------------
  1894.  *
  1895.  * TclIncrElementOfIndexedArray --
  1896.  *
  1897.  *    Increments the Tcl object value of an element in a local array
  1898.  *    variable. The element is named by the object elemPtr while the array
  1899.  *    is specified by its index in the active procedure's array of
  1900.  *    compiler allocated local variables.
  1901.  *
  1902.  * Results:
  1903.  *    Returns a pointer to the Tcl_Obj holding the new value of the
  1904.  *    element. If the specified array or element doesn't exist, or there
  1905.  *    is a clash in array usage, or an error occurs while executing
  1906.  *    variable traces, then NULL is returned and a message will be left in
  1907.  *    the interpreter's result.
  1908.  *
  1909.  * Side effects:
  1910.  *    The value of the given array element is incremented by the specified
  1911.  *    amount. The ref count for the returned object is _not_ incremented
  1912.  *    to reflect the returned reference; if you want to keep a reference
  1913.  *    to the object you must increment its ref count yourself. If the
  1914.  *    entry doesn't exist then a new variable is created.
  1915.  *
  1916.  *----------------------------------------------------------------------
  1917.  */
  1918.  
  1919. Tcl_Obj *
  1920. TclIncrElementOfIndexedArray(interp, localIndex, elemPtr, incrAmount)
  1921.     Tcl_Interp *interp;        /* Command interpreter in which the array is
  1922.                  * to be found. */
  1923.     int localIndex;        /* Index of array variable in procedure's
  1924.                  * array of local variables. */
  1925.     Tcl_Obj *elemPtr;        /* Points to an object holding the name of
  1926.                  * an element to increment in the array. */
  1927.     long incrAmount;        /* Amount to be added to variable. */
  1928. {
  1929.     register Tcl_Obj *varValuePtr;
  1930.     Tcl_Obj *resultPtr;
  1931.     int createdNewObj;        /* Set 1 if var's value object is shared
  1932.                  * so we must increment a copy (i.e. copy
  1933.                  * on write). */
  1934.     long i;
  1935.     int result;
  1936.  
  1937.     varValuePtr = TclGetElementOfIndexedArray(interp, localIndex, elemPtr,
  1938.                               /*leaveErrorMsg*/ 1);
  1939.     if (varValuePtr == NULL) {
  1940.     Tcl_AddObjErrorInfo(interp,
  1941.         "\n    (reading value of variable to increment)", -1);
  1942.     return NULL;
  1943.     }
  1944.  
  1945.     /*
  1946.      * Reach into the object's representation to extract and increment the
  1947.      * variable's value. If the object is unshared we can modify it
  1948.      * directly, otherwise we must create a new copy to modify: this is
  1949.      * "copy on write". Then free the variable's old string representation,
  1950.      * if any, since it will no longer be valid.
  1951.      */
  1952.  
  1953.     createdNewObj = 0;
  1954.     if (Tcl_IsShared(varValuePtr)) {
  1955.     createdNewObj = 1;
  1956.     varValuePtr = Tcl_DuplicateObj(varValuePtr);
  1957.     }
  1958.     result = Tcl_GetLongFromObj(interp, varValuePtr, &i);
  1959.     if (result != TCL_OK) {
  1960.     if (createdNewObj) {
  1961.         Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */
  1962.     }
  1963.     return NULL;
  1964.     }
  1965.     Tcl_SetLongObj(varValuePtr, (i + incrAmount));
  1966.     
  1967.     /*
  1968.      * Store the variable's new value and run any write traces.
  1969.      */
  1970.     
  1971.     resultPtr = TclSetElementOfIndexedArray(interp, localIndex, elemPtr,
  1972.                         varValuePtr,
  1973.                                             /*leaveErrorMsg*/ 1);
  1974.     if (resultPtr == NULL) {
  1975.     return NULL;
  1976.     }
  1977.     return resultPtr;
  1978. }
  1979.  
  1980. /*
  1981.  *----------------------------------------------------------------------
  1982.  *
  1983.  * Tcl_UnsetVar --
  1984.  *
  1985.  *    Delete a variable, so that it may not be accessed anymore.
  1986.  *
  1987.  * Results:
  1988.  *    Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
  1989.  *    if the variable can't be unset.  In the event of an error,
  1990.  *    if the TCL_LEAVE_ERR_MSG flag is set then an error message
  1991.  *    is left in interp->result.
  1992.  *
  1993.  * Side effects:
  1994.  *    If varName is defined as a local or global variable in interp,
  1995.  *    it is deleted.
  1996.  *
  1997.  *----------------------------------------------------------------------
  1998.  */
  1999.  
  2000. int
  2001. Tcl_UnsetVar(interp, varName, flags)
  2002.     Tcl_Interp *interp;        /* Command interpreter in which varName is
  2003.                  * to be looked up. */
  2004.     char *varName;        /* Name of a variable in interp.  May be
  2005.                  * either a scalar name or an array name
  2006.                  * or an element in an array. */
  2007.     int flags;            /* OR-ed combination of any of
  2008.                  * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY or
  2009.                  * TCL_LEAVE_ERR_MSG. */
  2010. {
  2011.     return Tcl_UnsetVar2(interp, varName, (char *) NULL,
  2012.         (flags | TCL_PARSE_PART1));
  2013. }
  2014.  
  2015. /*
  2016.  *----------------------------------------------------------------------
  2017.  *
  2018.  * Tcl_UnsetVar2 --
  2019.  *
  2020.  *    Delete a variable, given a 2-part name.
  2021.  *
  2022.  * Results:
  2023.  *    Returns TCL_OK if the variable was successfully deleted, TCL_ERROR
  2024.  *    if the variable can't be unset.  In the event of an error,
  2025.  *    if the TCL_LEAVE_ERR_MSG flag is set then an error message
  2026.  *    is left in interp->result.
  2027.  *
  2028.  * Side effects:
  2029.  *    If part1 and part2 indicate a local or global variable in interp,
  2030.  *    it is deleted.  If part1 is an array name and part2 is NULL, then
  2031.  *    the whole array is deleted.
  2032.  *
  2033.  *----------------------------------------------------------------------
  2034.  */
  2035.  
  2036. int
  2037. Tcl_UnsetVar2(interp, part1, part2, flags)
  2038.     Tcl_Interp *interp;        /* Command interpreter in which varName is
  2039.                  * to be looked up. */
  2040.     char *part1;        /* Name of variable or array. */
  2041.     char *part2;        /* Name of element within array or NULL. */
  2042.     int flags;            /* OR-ed combination of any of
  2043.                  * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
  2044.                  * TCL_LEAVE_ERR_MSG, or
  2045.                  * TCL_PARSE_PART1. */
  2046. {
  2047.     Var dummyVar;
  2048.     Var *varPtr, *dummyVarPtr;
  2049.     Interp *iPtr = (Interp *) interp;
  2050.     Var *arrayPtr;
  2051.     ActiveVarTrace *activePtr;
  2052.     Tcl_Obj *objPtr;
  2053.     int result;
  2054.  
  2055.     varPtr = TclLookupVar(interp, part1, part2, flags, "unset",
  2056.         /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
  2057.     if (varPtr == NULL) {
  2058.     return TCL_ERROR;
  2059.     }
  2060.     result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK);
  2061.  
  2062.     if ((arrayPtr != NULL) && (arrayPtr->searchPtr != NULL)) {
  2063.     DeleteSearches(arrayPtr);
  2064.     }
  2065.  
  2066.     /*
  2067.      * The code below is tricky, because of the possibility that
  2068.      * a trace procedure might try to access a variable being
  2069.      * deleted. To handle this situation gracefully, do things
  2070.      * in three steps:
  2071.      * 1. Copy the contents of the variable to a dummy variable
  2072.      *    structure, and mark the original Var structure as undefined.
  2073.      * 2. Invoke traces and clean up the variable, using the dummy copy.
  2074.      * 3. If at the end of this the original variable is still
  2075.      *    undefined and has no outstanding references, then delete
  2076.      *      it (but it could have gotten recreated by a trace).
  2077.      */
  2078.  
  2079.     dummyVar = *varPtr;
  2080.     TclSetVarUndefined(varPtr);
  2081.     TclSetVarScalar(varPtr);
  2082.     varPtr->value.objPtr = NULL; /* dummyVar points to any value object */
  2083.     varPtr->tracePtr = NULL;
  2084.     varPtr->searchPtr = NULL;
  2085.  
  2086.     /*
  2087.      * Call trace procedures for the variable being deleted. Then delete
  2088.      * its traces. Be sure to abort any other traces for the variable
  2089.      * that are still pending. Special tricks:
  2090.      * 1. We need to increment varPtr's refCount around this: CallTraces
  2091.      *    will use dummyVar so it won't increment varPtr's refCount itself.
  2092.      * 2. Turn off the VAR_TRACE_ACTIVE flag in dummyVar: we want to
  2093.      *    call unset traces even if other traces are pending.
  2094.      */
  2095.  
  2096.     if ((dummyVar.tracePtr != NULL)
  2097.         || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) {
  2098.     varPtr->refCount++;
  2099.     dummyVar.flags &= ~VAR_TRACE_ACTIVE;
  2100.     (void) CallTraces(iPtr, arrayPtr, &dummyVar, part1, part2,
  2101.         (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1)) | TCL_TRACE_UNSETS);
  2102.     while (dummyVar.tracePtr != NULL) {
  2103.         VarTrace *tracePtr = dummyVar.tracePtr;
  2104.         dummyVar.tracePtr = tracePtr->nextPtr;
  2105.         ckfree((char *) tracePtr);
  2106.     }
  2107.     for (activePtr = iPtr->activeTracePtr;  activePtr != NULL;
  2108.         activePtr = activePtr->nextPtr) {
  2109.         if (activePtr->varPtr == varPtr) {
  2110.         activePtr->nextTracePtr = NULL;
  2111.         }
  2112.     }
  2113.     varPtr->refCount--;
  2114.     }
  2115.  
  2116.     /*
  2117.      * If the variable is an array, delete all of its elements. This must be
  2118.      * done after calling the traces on the array, above (that's the way
  2119.      * traces are defined). If it is a scalar, "discard" its object
  2120.      * (decrement the ref count of its object, if any).
  2121.      */
  2122.  
  2123.     dummyVarPtr = &dummyVar;
  2124.     if (TclIsVarArray(dummyVarPtr) && !TclIsVarUndefined(dummyVarPtr)) {
  2125.     DeleteArray(iPtr, part1, dummyVarPtr,
  2126.         (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS);
  2127.     }
  2128.     if (TclIsVarScalar(dummyVarPtr)
  2129.         && (dummyVarPtr->value.objPtr != NULL)) {
  2130.     objPtr = dummyVarPtr->value.objPtr;
  2131.     TclDecrRefCount(objPtr);
  2132.     dummyVarPtr->value.objPtr = NULL;
  2133.     }
  2134.  
  2135.     /*
  2136.      * If the variable was a namespace variable, decrement its reference
  2137.      * count. We are in the process of destroying its namespace so that
  2138.      * namespace will no longer "refer" to the variable.
  2139.      */
  2140.     
  2141.     if (varPtr->flags & VAR_NAMESPACE_VAR) {
  2142.     varPtr->flags &= ~VAR_NAMESPACE_VAR;
  2143.     varPtr->refCount--;
  2144.     }
  2145.  
  2146.     /*
  2147.      * It's an error to unset an undefined variable.
  2148.      */
  2149.     
  2150.     if (result != TCL_OK) {
  2151.     if (flags & TCL_LEAVE_ERR_MSG) {
  2152.         VarErrMsg(interp, part1, part2, "unset", 
  2153.             ((arrayPtr == NULL) ? noSuchVar : noSuchElement));
  2154.     }
  2155.     }
  2156.  
  2157.     /*
  2158.      * Finally, if the variable is truly not in use then free up its Var
  2159.      * structure and remove it from its hash table, if any. The ref count of
  2160.      * its value object, if any, was decremented above.
  2161.      */
  2162.  
  2163.     CleanupVar(varPtr, arrayPtr);
  2164.     return result;
  2165. }
  2166.  
  2167. /*
  2168.  *----------------------------------------------------------------------
  2169.  *
  2170.  * Tcl_TraceVar --
  2171.  *
  2172.  *    Arrange for reads and/or writes to a variable to cause a
  2173.  *    procedure to be invoked, which can monitor the operations
  2174.  *    and/or change their actions.
  2175.  *
  2176.  * Results:
  2177.  *    A standard Tcl return value.
  2178.  *
  2179.  * Side effects:
  2180.  *    A trace is set up on the variable given by varName, such that
  2181.  *    future references to the variable will be intermediated by
  2182.  *    proc.  See the manual entry for complete details on the calling
  2183.  *    sequence for proc.
  2184.  *
  2185.  *----------------------------------------------------------------------
  2186.  */
  2187.  
  2188. int
  2189. Tcl_TraceVar(interp, varName, flags, proc, clientData)
  2190.     Tcl_Interp *interp;        /* Interpreter in which variable is
  2191.                  * to be traced. */
  2192.     char *varName;        /* Name of variable;  may end with "(index)"
  2193.                  * to signify an array reference. */
  2194.     int flags;            /* OR-ed collection of bits, including any
  2195.                  * of TCL_TRACE_READS, TCL_TRACE_WRITES,
  2196.                  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, and
  2197.                  * TCL_NAMESPACE_ONLY. */
  2198.     Tcl_VarTraceProc *proc;    /* Procedure to call when specified ops are
  2199.                  * invoked upon varName. */
  2200.     ClientData clientData;    /* Arbitrary argument to pass to proc. */
  2201. {
  2202.     return Tcl_TraceVar2(interp, varName, (char *) NULL,
  2203.         (flags | TCL_PARSE_PART1), proc, clientData);
  2204. }
  2205.  
  2206. /*
  2207.  *----------------------------------------------------------------------
  2208.  *
  2209.  * Tcl_TraceVar2 --
  2210.  *
  2211.  *    Arrange for reads and/or writes to a variable to cause a
  2212.  *    procedure to be invoked, which can monitor the operations
  2213.  *    and/or change their actions.
  2214.  *
  2215.  * Results:
  2216.  *    A standard Tcl return value.
  2217.  *
  2218.  * Side effects:
  2219.  *    A trace is set up on the variable given by part1 and part2, such
  2220.  *    that future references to the variable will be intermediated by
  2221.  *    proc.  See the manual entry for complete details on the calling
  2222.  *    sequence for proc.
  2223.  *
  2224.  *----------------------------------------------------------------------
  2225.  */
  2226.  
  2227. int
  2228. Tcl_TraceVar2(interp, part1, part2, flags, proc, clientData)
  2229.     Tcl_Interp *interp;        /* Interpreter in which variable is
  2230.                  * to be traced. */
  2231.     char *part1;        /* Name of scalar variable or array. */
  2232.     char *part2;        /* Name of element within array;  NULL means
  2233.                  * trace applies to scalar variable or array
  2234.                  * as-a-whole. */
  2235.     int flags;            /* OR-ed collection of bits, including any
  2236.                  * of TCL_TRACE_READS, TCL_TRACE_WRITES,
  2237.                  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY,
  2238.                  * TCL_NAMESPACE_ONLY and
  2239.                  * TCL_PARSE_PART1. */
  2240.     Tcl_VarTraceProc *proc;    /* Procedure to call when specified ops are
  2241.                  * invoked upon varName. */
  2242.     ClientData clientData;    /* Arbitrary argument to pass to proc. */
  2243. {
  2244.     Var *varPtr, *arrayPtr;
  2245.     register VarTrace *tracePtr;
  2246.  
  2247.     varPtr = TclLookupVar(interp, part1, part2, (flags | TCL_LEAVE_ERR_MSG),
  2248.         "trace", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
  2249.     if (varPtr == NULL) {
  2250.     return TCL_ERROR;
  2251.     }
  2252.  
  2253.     /*
  2254.      * Set up trace information.
  2255.      */
  2256.  
  2257.     tracePtr = (VarTrace *) ckalloc(sizeof(VarTrace));
  2258.     tracePtr->traceProc = proc;
  2259.     tracePtr->clientData = clientData;
  2260.     tracePtr->flags = 
  2261.         flags & (TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS);
  2262.     tracePtr->nextPtr = varPtr->tracePtr;
  2263.     varPtr->tracePtr = tracePtr;
  2264.     return TCL_OK;
  2265. }
  2266.  
  2267. /*
  2268.  *----------------------------------------------------------------------
  2269.  *
  2270.  * Tcl_UntraceVar --
  2271.  *
  2272.  *    Remove a previously-created trace for a variable.
  2273.  *
  2274.  * Results:
  2275.  *    None.
  2276.  *
  2277.  * Side effects:
  2278.  *    If there exists a trace for the variable given by varName
  2279.  *    with the given flags, proc, and clientData, then that trace
  2280.  *    is removed.
  2281.  *
  2282.  *----------------------------------------------------------------------
  2283.  */
  2284.  
  2285. void
  2286. Tcl_UntraceVar(interp, varName, flags, proc, clientData)
  2287.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2288.     char *varName;        /* Name of variable; may end with "(index)"
  2289.                  * to signify an array reference. */
  2290.     int flags;            /* OR-ed collection of bits describing
  2291.                  * current trace, including any of
  2292.                  * TCL_TRACE_READS, TCL_TRACE_WRITES,
  2293.                  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY
  2294.                  * and TCL_NAMESPACE_ONLY. */
  2295.     Tcl_VarTraceProc *proc;    /* Procedure assocated with trace. */
  2296.     ClientData clientData;    /* Arbitrary argument to pass to proc. */
  2297. {
  2298.     Tcl_UntraceVar2(interp, varName, (char *) NULL,
  2299.             (flags | TCL_PARSE_PART1), proc, clientData);
  2300. }
  2301.  
  2302. /*
  2303.  *----------------------------------------------------------------------
  2304.  *
  2305.  * Tcl_UntraceVar2 --
  2306.  *
  2307.  *    Remove a previously-created trace for a variable.
  2308.  *
  2309.  * Results:
  2310.  *    None.
  2311.  *
  2312.  * Side effects:
  2313.  *    If there exists a trace for the variable given by part1
  2314.  *    and part2 with the given flags, proc, and clientData, then
  2315.  *    that trace is removed.
  2316.  *
  2317.  *----------------------------------------------------------------------
  2318.  */
  2319.  
  2320. void
  2321. Tcl_UntraceVar2(interp, part1, part2, flags, proc, clientData)
  2322.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2323.     char *part1;        /* Name of variable or array. */
  2324.     char *part2;        /* Name of element within array;  NULL means
  2325.                  * trace applies to scalar variable or array
  2326.                  * as-a-whole. */
  2327.     int flags;            /* OR-ed collection of bits describing
  2328.                  * current trace, including any of
  2329.                  * TCL_TRACE_READS, TCL_TRACE_WRITES,
  2330.                  * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY,
  2331.                  * TCL_NAMESPACE_ONLY and
  2332.                  * TCL_PARSE_PART1. */
  2333.     Tcl_VarTraceProc *proc;    /* Procedure assocated with trace. */
  2334.     ClientData clientData;    /* Arbitrary argument to pass to proc. */
  2335. {
  2336.     register VarTrace *tracePtr;
  2337.     VarTrace *prevPtr;
  2338.     Var *varPtr, *arrayPtr;
  2339.     Interp *iPtr = (Interp *) interp;
  2340.     ActiveVarTrace *activePtr;
  2341.  
  2342.     varPtr = TclLookupVar(interp, part1, part2,
  2343.         flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1),
  2344.         /*msg*/ (char *) NULL,
  2345.         /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
  2346.     if (varPtr == NULL) {
  2347.     return;
  2348.     }
  2349.  
  2350.     flags &= (TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS);
  2351.     for (tracePtr = varPtr->tracePtr, prevPtr = NULL;  ;
  2352.         prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) {
  2353.     if (tracePtr == NULL) {
  2354.         return;
  2355.     }
  2356.     if ((tracePtr->traceProc == proc) && (tracePtr->flags == flags)
  2357.         && (tracePtr->clientData == clientData)) {
  2358.         break;
  2359.     }
  2360.     }
  2361.  
  2362.     /*
  2363.      * The code below makes it possible to delete traces while traces
  2364.      * are active: it makes sure that the deleted trace won't be
  2365.      * processed by CallTraces.
  2366.      */
  2367.  
  2368.     for (activePtr = iPtr->activeTracePtr;  activePtr != NULL;
  2369.         activePtr = activePtr->nextPtr) {
  2370.     if (activePtr->nextTracePtr == tracePtr) {
  2371.         activePtr->nextTracePtr = tracePtr->nextPtr;
  2372.     }
  2373.     }
  2374.     if (prevPtr == NULL) {
  2375.     varPtr->tracePtr = tracePtr->nextPtr;
  2376.     } else {
  2377.     prevPtr->nextPtr = tracePtr->nextPtr;
  2378.     }
  2379.     ckfree((char *) tracePtr);
  2380.  
  2381.     /*
  2382.      * If this is the last trace on the variable, and the variable is
  2383.      * unset and unused, then free up the variable.
  2384.      */
  2385.  
  2386.     if (TclIsVarUndefined(varPtr)) {
  2387.     CleanupVar(varPtr, (Var *) NULL);
  2388.     }
  2389. }
  2390.  
  2391. /*
  2392.  *----------------------------------------------------------------------
  2393.  *
  2394.  * Tcl_VarTraceInfo --
  2395.  *
  2396.  *    Return the clientData value associated with a trace on a
  2397.  *    variable.  This procedure can also be used to step through
  2398.  *    all of the traces on a particular variable that have the
  2399.  *    same trace procedure.
  2400.  *
  2401.  * Results:
  2402.  *    The return value is the clientData value associated with
  2403.  *    a trace on the given variable.  Information will only be
  2404.  *    returned for a trace with proc as trace procedure.  If
  2405.  *    the clientData argument is NULL then the first such trace is
  2406.  *    returned;  otherwise, the next relevant one after the one
  2407.  *    given by clientData will be returned.  If the variable
  2408.  *    doesn't exist, or if there are no (more) traces for it,
  2409.  *    then NULL is returned.
  2410.  *
  2411.  * Side effects:
  2412.  *    None.
  2413.  *
  2414.  *----------------------------------------------------------------------
  2415.  */
  2416.  
  2417. ClientData
  2418. Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData)
  2419.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2420.     char *varName;        /* Name of variable;  may end with "(index)"
  2421.                  * to signify an array reference. */
  2422.     int flags;            /* 0, TCL_GLOBAL_ONLY, or
  2423.                  * TCL_NAMESPACE_ONLY. */
  2424.     Tcl_VarTraceProc *proc;    /* Procedure assocated with trace. */
  2425.     ClientData prevClientData;    /* If non-NULL, gives last value returned
  2426.                  * by this procedure, so this call will
  2427.                  * return the next trace after that one.
  2428.                  * If NULL, this call will return the
  2429.                  * first trace. */
  2430. {
  2431.     return Tcl_VarTraceInfo2(interp, varName, (char *) NULL,
  2432.         (flags | TCL_PARSE_PART1), proc, prevClientData);
  2433. }
  2434.  
  2435. /*
  2436.  *----------------------------------------------------------------------
  2437.  *
  2438.  * Tcl_VarTraceInfo2 --
  2439.  *
  2440.  *    Same as Tcl_VarTraceInfo, except takes name in two pieces
  2441.  *    instead of one.
  2442.  *
  2443.  * Results:
  2444.  *    Same as Tcl_VarTraceInfo.
  2445.  *
  2446.  * Side effects:
  2447.  *    None.
  2448.  *
  2449.  *----------------------------------------------------------------------
  2450.  */
  2451.  
  2452. ClientData
  2453. Tcl_VarTraceInfo2(interp, part1, part2, flags, proc, prevClientData)
  2454.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2455.     char *part1;        /* Name of variable or array. */
  2456.     char *part2;        /* Name of element within array;  NULL means
  2457.                  * trace applies to scalar variable or array
  2458.                  * as-a-whole. */
  2459.     int flags;            /* OR-ed combination of TCL_GLOBAL_ONLY,
  2460.                  * TCL_NAMESPACE_ONLY, and
  2461.                  * TCL_PARSE_PART1. */
  2462.     Tcl_VarTraceProc *proc;    /* Procedure assocated with trace. */
  2463.     ClientData prevClientData;    /* If non-NULL, gives last value returned
  2464.                  * by this procedure, so this call will
  2465.                  * return the next trace after that one.
  2466.                  * If NULL, this call will return the
  2467.                  * first trace. */
  2468. {
  2469.     register VarTrace *tracePtr;
  2470.     Var *varPtr, *arrayPtr;
  2471.  
  2472.     varPtr = TclLookupVar(interp, part1, part2,
  2473.         flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_PARSE_PART1),
  2474.         /*msg*/ (char *) NULL,
  2475.         /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
  2476.     if (varPtr == NULL) {
  2477.     return NULL;
  2478.     }
  2479.  
  2480.     /*
  2481.      * Find the relevant trace, if any, and return its clientData.
  2482.      */
  2483.  
  2484.     tracePtr = varPtr->tracePtr;
  2485.     if (prevClientData != NULL) {
  2486.     for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
  2487.         if ((tracePtr->clientData == prevClientData)
  2488.             && (tracePtr->traceProc == proc)) {
  2489.         tracePtr = tracePtr->nextPtr;
  2490.         break;
  2491.         }
  2492.     }
  2493.     }
  2494.     for ( ;  tracePtr != NULL;  tracePtr = tracePtr->nextPtr) {
  2495.     if (tracePtr->traceProc == proc) {
  2496.         return tracePtr->clientData;
  2497.     }
  2498.     }
  2499.     return NULL;
  2500. }
  2501.  
  2502. /*
  2503.  *----------------------------------------------------------------------
  2504.  *
  2505.  * Tcl_UnsetObjCmd --
  2506.  *
  2507.  *    This object-based procedure is invoked to process the "unset" Tcl
  2508.  *    command. See the user documentation for details on what it does.
  2509.  *
  2510.  * Results:
  2511.  *    A standard Tcl object result value.
  2512.  *
  2513.  * Side effects:
  2514.  *    See the user documentation.
  2515.  *
  2516.  *----------------------------------------------------------------------
  2517.  */
  2518.  
  2519.     /* ARGSUSED */
  2520. int
  2521. Tcl_UnsetObjCmd(dummy, interp, objc, objv)
  2522.     ClientData dummy;        /* Not used. */
  2523.     Tcl_Interp *interp;        /* Current interpreter. */
  2524.     int objc;            /* Number of arguments. */
  2525.     Tcl_Obj *CONST objv[];    /* Argument objects. */
  2526. {
  2527.     register int i;
  2528.     register char *name;
  2529.  
  2530.     if (objc < 2) {
  2531.     Tcl_WrongNumArgs(interp, 1, objv, "varName ?varName ...?");
  2532.     return TCL_ERROR;
  2533.     }
  2534.     
  2535.     for (i = 1;  i < objc;  i++) {
  2536.     /*
  2537.      * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
  2538.      */
  2539.  
  2540.     name = Tcl_GetStringFromObj(objv[i], (int *) NULL);
  2541.     if (Tcl_UnsetVar2(interp, name, (char *) NULL,
  2542.             (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1)) != TCL_OK) {
  2543.         return TCL_ERROR;
  2544.     }
  2545.     }
  2546.     return TCL_OK;
  2547. }
  2548.  
  2549. /*
  2550.  *----------------------------------------------------------------------
  2551.  *
  2552.  * Tcl_AppendObjCmd --
  2553.  *
  2554.  *    This object-based procedure is invoked to process the "append" 
  2555.  *    Tcl command. See the user documentation for details on what it does.
  2556.  *
  2557.  * Results:
  2558.  *    A standard Tcl object result value.
  2559.  *
  2560.  * Side effects:
  2561.  *    A variable's value may be changed.
  2562.  *
  2563.  *----------------------------------------------------------------------
  2564.  */
  2565.  
  2566.     /* ARGSUSED */
  2567. int
  2568. Tcl_AppendObjCmd(dummy, interp, objc, objv)
  2569.     ClientData dummy;        /* Not used. */
  2570.     Tcl_Interp *interp;        /* Current interpreter. */
  2571.     int objc;            /* Number of arguments. */
  2572.     Tcl_Obj *CONST objv[];    /* Argument objects. */
  2573. {
  2574.     register Tcl_Obj *varValuePtr = NULL;
  2575.                         /* Initialized to avoid compiler
  2576.                          * warning. */
  2577.     int i;
  2578.  
  2579.     if (objc < 2) {
  2580.     Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?");
  2581.     return TCL_ERROR;
  2582.     }
  2583.  
  2584.     if (objc == 2) {
  2585.     varValuePtr = Tcl_ObjGetVar2(interp, objv[1], (Tcl_Obj *) NULL,
  2586.             (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
  2587.     if (varValuePtr == NULL) {
  2588.         return TCL_ERROR;
  2589.     }
  2590.     } else {
  2591.     for (i = 2;  i < objc;  i++) {
  2592.         varValuePtr = Tcl_ObjSetVar2(interp, objv[1], (Tcl_Obj *) NULL,
  2593.         objv[i],
  2594.         (TCL_APPEND_VALUE | TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
  2595.         if (varValuePtr == NULL) {
  2596.         return TCL_ERROR;
  2597.         }
  2598.     }
  2599.     }
  2600.     
  2601.     Tcl_SetObjResult(interp, varValuePtr);
  2602.     return TCL_OK;
  2603. }
  2604.  
  2605. /*
  2606.  *----------------------------------------------------------------------
  2607.  *
  2608.  * Tcl_LappendObjCmd --
  2609.  *
  2610.  *    This object-based procedure is invoked to process the "lappend" 
  2611.  *    Tcl command. See the user documentation for details on what it does.
  2612.  *
  2613.  * Results:
  2614.  *    A standard Tcl object result value.
  2615.  *
  2616.  * Side effects:
  2617.  *    A variable's value may be changed.
  2618.  *
  2619.  *----------------------------------------------------------------------
  2620.  */
  2621.  
  2622.     /* ARGSUSED */
  2623. int
  2624. Tcl_LappendObjCmd(dummy, interp, objc, objv)
  2625.     ClientData dummy;        /* Not used. */
  2626.     Tcl_Interp *interp;        /* Current interpreter. */
  2627.     int objc;            /* Number of arguments. */
  2628.     Tcl_Obj *CONST objv[];    /* Argument objects. */
  2629. {
  2630.     Tcl_Obj *varValuePtr, *newValuePtr;
  2631.     register List *listRepPtr;
  2632.     register Tcl_Obj **elemPtrs;
  2633.     int numElems, numRequired, createdNewObj, i, j;
  2634.  
  2635.     if (objc < 2) {
  2636.     Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?");
  2637.     return TCL_ERROR;
  2638.     }
  2639.     
  2640.     if (objc == 2) {
  2641.     newValuePtr = Tcl_ObjGetVar2(interp, objv[1], (Tcl_Obj *) NULL,
  2642.         (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
  2643.     if (newValuePtr == NULL) {
  2644.         /*
  2645.          * The variable doesn't exist yet. Just create it with an empty
  2646.          * initial value.
  2647.          */
  2648.         
  2649.         Tcl_Obj *nullObjPtr = Tcl_NewObj();
  2650.         newValuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL,
  2651.             nullObjPtr, (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
  2652.         if (newValuePtr == NULL) {
  2653.         Tcl_DecrRefCount(nullObjPtr); /* free unneeded object */
  2654.         return TCL_ERROR;
  2655.         }
  2656.     }
  2657.     } else {
  2658.     /*
  2659.      * We have arguments to append. We used to call Tcl_ObjSetVar2 to
  2660.      * append each argument one at a time to ensure that traces were run
  2661.      * for each append step. We now append the arguments all at once
  2662.      * because it's faster. Note that a read trace and a write trace for
  2663.      * the variable will now each only be called once. Also, if the
  2664.      * variable's old value is unshared we modify it directly, otherwise
  2665.      * we create a new copy to modify: this is "copy on write".
  2666.      */
  2667.  
  2668.     createdNewObj = 0;
  2669.     varValuePtr = Tcl_ObjGetVar2(interp, objv[1], (Tcl_Obj *) NULL,
  2670.             TCL_PARSE_PART1);
  2671.     if (varValuePtr == NULL) { /* no old value: append to new obj */
  2672.         varValuePtr = Tcl_NewObj(); 
  2673.         createdNewObj = 1;
  2674.     } else if (Tcl_IsShared(varValuePtr)) {    
  2675.         varValuePtr = Tcl_DuplicateObj(varValuePtr);
  2676.         createdNewObj = 1;
  2677.     }
  2678.  
  2679.     /*
  2680.      * Convert the variable's old value to a list object if necessary.
  2681.      */
  2682.  
  2683.     if (varValuePtr->typePtr != &tclListType) {
  2684.         int result = tclListType.setFromAnyProc(interp, varValuePtr);
  2685.         if (result != TCL_OK) {
  2686.         if (createdNewObj) {
  2687.             Tcl_DecrRefCount(varValuePtr); /* free unneeded obj. */
  2688.         }
  2689.         return result;
  2690.         }
  2691.     }
  2692.     listRepPtr = (List *) varValuePtr->internalRep.otherValuePtr;
  2693.     elemPtrs = listRepPtr->elements;
  2694.     numElems = listRepPtr->elemCount;
  2695.  
  2696.     /*
  2697.      * If there is no room in the current array of element pointers,
  2698.      * allocate a new, larger array and copy the pointers to it.
  2699.      */
  2700.     
  2701.     numRequired = numElems + (objc-2);
  2702.     if (numRequired > listRepPtr->maxElemCount) {
  2703.         int newMax = (2 * numRequired);
  2704.         Tcl_Obj **newElemPtrs = (Tcl_Obj **)
  2705.             ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *)));
  2706.         
  2707.         memcpy((VOID *) newElemPtrs, (VOID *) elemPtrs,
  2708.             (size_t) (numElems * sizeof(Tcl_Obj *)));
  2709.         listRepPtr->maxElemCount = newMax;
  2710.         listRepPtr->elements = newElemPtrs;
  2711.         ckfree((char *) elemPtrs);
  2712.         elemPtrs = newElemPtrs;
  2713.     }
  2714.  
  2715.     /*
  2716.      * Insert the new elements at the end of the list.
  2717.      */
  2718.  
  2719.     for (i = 2, j = numElems;  i < objc;  i++, j++) {
  2720.             elemPtrs[j] = objv[i];
  2721.             Tcl_IncrRefCount(objv[i]);
  2722.         }
  2723.     listRepPtr->elemCount = numRequired;
  2724.  
  2725.     /*
  2726.      * Invalidate and free any old string representation since it no
  2727.      * longer reflects the list's internal representation.
  2728.      */
  2729.  
  2730.     Tcl_InvalidateStringRep(varValuePtr);
  2731.  
  2732.     /*
  2733.      * Now store the list object back into the variable. If there is an
  2734.      * error setting the new value, decrement its ref count if it
  2735.      * was new.
  2736.      */
  2737.     
  2738.     newValuePtr = Tcl_ObjSetVar2(interp, objv[1], (Tcl_Obj *) NULL,
  2739.         varValuePtr, (TCL_LEAVE_ERR_MSG | TCL_PARSE_PART1));
  2740.     if (newValuePtr == NULL) {
  2741.         if (createdNewObj) {
  2742.         Tcl_DecrRefCount(varValuePtr); /* free unneeded obj */
  2743.         }
  2744.         return TCL_ERROR;
  2745.     }
  2746.     }
  2747.  
  2748.     /*
  2749.      * Set the interpreter's object result to refer to the variable's value
  2750.      * object.
  2751.      */
  2752.  
  2753.     Tcl_SetObjResult(interp, newValuePtr);
  2754.     return TCL_OK;
  2755. }
  2756.  
  2757. /*
  2758.  *----------------------------------------------------------------------
  2759.  *
  2760.  * Tcl_ArrayObjCmd --
  2761.  *
  2762.  *    This object-based procedure is invoked to process the "array" Tcl
  2763.  *    command. See the user documentation for details on what it does.
  2764.  *
  2765.  * Results:
  2766.  *    A standard Tcl result object.
  2767.  *
  2768.  * Side effects:
  2769.  *    See the user documentation.
  2770.  *
  2771.  *----------------------------------------------------------------------
  2772.  */
  2773.  
  2774.     /* ARGSUSED */
  2775. int
  2776. Tcl_ArrayObjCmd(dummy, interp, objc, objv)
  2777.     ClientData dummy;        /* Not used. */
  2778.     Tcl_Interp *interp;        /* Current interpreter. */
  2779.     int objc;            /* Number of arguments. */
  2780.     Tcl_Obj *CONST objv[];    /* Argument objects. */
  2781. {
  2782.     static char *arrayOptions[] = {"anymore", "donesearch", "exists", "get", 
  2783.             "names", "nextelement", "set", "size", "startsearch", 
  2784.             (char *) NULL};
  2785.     Var *varPtr, *arrayPtr;
  2786.     Tcl_HashEntry *hPtr;
  2787.     Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
  2788.     int notArray;
  2789.     char *varName;
  2790.     int index, result;
  2791.  
  2792.  
  2793.     if (objc < 3) {
  2794.     Tcl_WrongNumArgs(interp, 1, objv, "option arrayName ?arg ...?");
  2795.     return TCL_ERROR;
  2796.     }
  2797.  
  2798.     if (Tcl_GetIndexFromObj(interp, objv[1], arrayOptions, "option", 0, &index)
  2799.         != TCL_OK) {
  2800.         return TCL_ERROR;
  2801.     }
  2802.  
  2803.     /*
  2804.      * Locate the array variable (and it better be an array).
  2805.      * THIS FAILS IF A NAME OBJECT'S STRING REP HAS A NULL BYTE.
  2806.      */
  2807.     varName = TclGetStringFromObj(objv[2], (int *) NULL);
  2808.     varPtr = TclLookupVar(interp, varName, (char *) NULL, /*flags*/ 0,
  2809.             /*msg*/ 0, /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr);
  2810.  
  2811.     notArray = 0;
  2812.     if (varPtr == NULL) {
  2813.     notArray = 1;
  2814.     } else {
  2815.     if (!TclIsVarArray(varPtr)) {
  2816.         notArray = 1;
  2817.     }
  2818.     }
  2819.  
  2820.     switch (index) {
  2821.         case 0: {        /* anymore */
  2822.         ArraySearch *searchPtr;
  2823.         char *searchId;
  2824.         
  2825.         if (objc != 4) {
  2826.             Tcl_WrongNumArgs(interp, 2, objv, 
  2827.                         "arrayName searchId");
  2828.         return TCL_ERROR;
  2829.         }
  2830.         if (notArray) {
  2831.             goto error;
  2832.         }
  2833.         searchId = Tcl_GetStringFromObj(objv[3], (int *) NULL);
  2834.         searchPtr = ParseSearchId(interp, varPtr, varName, searchId);
  2835.         if (searchPtr == NULL) {
  2836.             return TCL_ERROR;
  2837.         }
  2838.         while (1) {
  2839.             Var *varPtr2;
  2840.  
  2841.         if (searchPtr->nextEntry != NULL) {
  2842.             varPtr2 = (Var *) Tcl_GetHashValue(searchPtr->nextEntry);
  2843.             if (!TclIsVarUndefined(varPtr2)) {
  2844.                 break;
  2845.             }
  2846.         }
  2847.         searchPtr->nextEntry = Tcl_NextHashEntry(&searchPtr->search);
  2848.         if (searchPtr->nextEntry == NULL) {
  2849.             Tcl_SetIntObj(resultPtr, 0);
  2850.             return TCL_OK;
  2851.         }
  2852.         }
  2853.         Tcl_SetIntObj(resultPtr, 1);
  2854.         break;
  2855.     }
  2856.         case 1: {        /* donesearch */
  2857.         ArraySearch *searchPtr, *prevPtr;
  2858.         char *searchId;
  2859.  
  2860.         if (objc != 4) {
  2861.             Tcl_WrongNumArgs(interp, 2, objv, 
  2862.                         "arrayName searchId");
  2863.         return TCL_ERROR;
  2864.         }
  2865.         if (notArray) {
  2866.             goto error;
  2867.         }
  2868.         searchId = Tcl_GetStringFromObj(objv[3], (int *) NULL);
  2869.         searchPtr = ParseSearchId(interp, varPtr, varName, searchId);
  2870.         if (searchPtr == NULL) {
  2871.             return TCL_ERROR;
  2872.         }
  2873.         if (varPtr->searchPtr == searchPtr) {
  2874.             varPtr->searchPtr = searchPtr->nextPtr;
  2875.         } else {
  2876.             for (prevPtr = varPtr->searchPtr;  ;
  2877.                 prevPtr = prevPtr->nextPtr) {
  2878.             if (prevPtr->nextPtr == searchPtr) {
  2879.                 prevPtr->nextPtr = searchPtr->nextPtr;
  2880.             break;
  2881.             }
  2882.         }
  2883.         }
  2884.         ckfree((char *) searchPtr);
  2885.         break;
  2886.     }
  2887.         case 2: {        /* exists */
  2888.         if (objc != 3) {
  2889.             Tcl_WrongNumArgs(interp, 2, objv, "arrayName");
  2890.             return TCL_ERROR;
  2891.         }
  2892.         Tcl_SetIntObj(resultPtr, !notArray);
  2893.         break;
  2894.     }
  2895.         case 3: {        /*get*/
  2896.         Tcl_HashSearch search;
  2897.         Var *varPtr2;
  2898.         char *pattern = NULL;
  2899.         char *name;
  2900.         Tcl_Obj *namePtr, *valuePtr;
  2901.         
  2902.         if ((objc != 3) && (objc != 4)) {
  2903.             Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?");
  2904.         return TCL_ERROR;
  2905.         }
  2906.         if (notArray) {
  2907.             return TCL_OK;
  2908.         }
  2909.         if (objc == 4) {
  2910.             pattern = Tcl_GetStringFromObj(objv[3], (int *) NULL);
  2911.         }
  2912.         for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
  2913.             hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {
  2914.             varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
  2915.         if (TclIsVarUndefined(varPtr2)) {
  2916.             continue;
  2917.         }
  2918.         name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
  2919.         if ((objc == 4) && !Tcl_StringMatch(name, pattern)) {
  2920.             continue;    /* element name doesn't match pattern */
  2921.         }
  2922.         
  2923.         namePtr = Tcl_NewStringObj(name, -1);
  2924.         result = Tcl_ListObjAppendElement(interp, resultPtr, namePtr);
  2925.         if (result != TCL_OK) {
  2926.             Tcl_DecrRefCount(namePtr); /* free unneeded name object */
  2927.             return result;
  2928.         }
  2929.         
  2930.         if (varPtr2->value.objPtr == NULL) {
  2931.              TclNewObj(valuePtr);
  2932.         } else {
  2933.             valuePtr = varPtr2->value.objPtr;
  2934.         }
  2935.         result = Tcl_ListObjAppendElement(interp, resultPtr, valuePtr);
  2936.         if (result != TCL_OK) {
  2937.             if (varPtr2->value.objPtr == NULL) {
  2938.                 Tcl_DecrRefCount(valuePtr); /* free unneeded object */
  2939.             }
  2940.             return result;
  2941.         }
  2942.         }
  2943.         break;
  2944.     }
  2945.         case 4: {        /* names */
  2946.         Tcl_HashSearch search;
  2947.         Var *varPtr2;
  2948.         char *pattern = NULL;
  2949.         char *name;
  2950.         Tcl_Obj *namePtr;
  2951.         
  2952.         if ((objc != 3) && (objc != 4)) {
  2953.               Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?");
  2954.         return TCL_ERROR;
  2955.         }
  2956.         if (notArray) {
  2957.             return TCL_OK;
  2958.         }
  2959.         if (objc == 4) {
  2960.             pattern = Tcl_GetStringFromObj(objv[3], (int *) NULL);
  2961.         }
  2962.         for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
  2963.             hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  2964.             varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
  2965.         if (TclIsVarUndefined(varPtr2)) {
  2966.             continue;
  2967.         }
  2968.         name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr);
  2969.         if ((objc == 4) && !Tcl_StringMatch(name, pattern)) {
  2970.              continue;    /* element name doesn't match pattern */
  2971.         }
  2972.         
  2973.         namePtr = Tcl_NewStringObj(name, -1);
  2974.         result = Tcl_ListObjAppendElement(interp, resultPtr, namePtr);
  2975.         if (result != TCL_OK) {
  2976.             Tcl_DecrRefCount(namePtr); /* free unneeded name object */
  2977.             return result;
  2978.         }
  2979.         }
  2980.         break;
  2981.     }
  2982.         case 5: {        /*nextelement*/
  2983.         ArraySearch *searchPtr;
  2984.         char *searchId;
  2985.         Tcl_HashEntry *hPtr;
  2986.         
  2987.         if (objc != 4) {
  2988.             Tcl_WrongNumArgs(interp, 2, objv, 
  2989.                         "arrayName searchId");
  2990.         return TCL_ERROR;
  2991.         }
  2992.         if (notArray) {
  2993.               goto error;
  2994.         }
  2995.         searchId = Tcl_GetStringFromObj(objv[3], (int *) NULL);
  2996.         searchPtr = ParseSearchId(interp, varPtr, varName, searchId);
  2997.         if (searchPtr == NULL) {
  2998.             return TCL_ERROR;
  2999.         }
  3000.         while (1) {
  3001.             Var *varPtr2;
  3002.  
  3003.         hPtr = searchPtr->nextEntry;
  3004.         if (hPtr == NULL) {
  3005.             hPtr = Tcl_NextHashEntry(&searchPtr->search);
  3006.             if (hPtr == NULL) {
  3007.                 return TCL_OK;
  3008.             }
  3009.         } else {
  3010.             searchPtr->nextEntry = NULL;
  3011.         }
  3012.         varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
  3013.         if (!TclIsVarUndefined(varPtr2)) {
  3014.             break;
  3015.         }
  3016.         }
  3017.         Tcl_SetStringObj(resultPtr,
  3018.                 Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), -1);
  3019.         break;
  3020.     }
  3021.         case 6: {        /*set*/
  3022.         Tcl_Obj **elemPtrs;
  3023.         int listLen, i, result;
  3024.         
  3025.         if (objc != 4) {
  3026.             Tcl_WrongNumArgs(interp, 2, objv, "arrayName list");
  3027.         return TCL_ERROR;
  3028.         }
  3029.         result = Tcl_ListObjGetElements(interp, objv[3], &listLen, 
  3030.                     &elemPtrs);
  3031.         if (result != TCL_OK) {
  3032.             return result;
  3033.         }
  3034.         if (listLen & 1) {
  3035.             Tcl_ResetResult(interp);
  3036.         Tcl_AppendToObj(Tcl_GetObjResult(interp),
  3037.                         "list must have an even number of elements", -1);
  3038.         return TCL_ERROR;
  3039.         }
  3040.         for (i = 0;  i < listLen;  i += 2) {
  3041.             if (Tcl_ObjSetVar2(interp, objv[2], elemPtrs[i], elemPtrs[i+1],
  3042.                 TCL_LEAVE_ERR_MSG) == NULL) {
  3043.             result = TCL_ERROR;
  3044.             break;
  3045.         }
  3046.         }
  3047.         return result;
  3048.     }
  3049.         case 7: {        /*size*/
  3050.         Tcl_HashSearch search;
  3051.         Var *varPtr2;
  3052.         int size;
  3053.  
  3054.         if (objc != 3) {
  3055.             Tcl_WrongNumArgs(interp, 2, objv, "arrayName");
  3056.         return TCL_ERROR;
  3057.         }
  3058.         size = 0;
  3059.         if (!notArray) {
  3060.             for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, 
  3061.                         &search);
  3062.                 hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {
  3063.             varPtr2 = (Var *) Tcl_GetHashValue(hPtr);
  3064.             if (TclIsVarUndefined(varPtr2)) {
  3065.                 continue;
  3066.             }
  3067.             size++;
  3068.         }
  3069.         }
  3070.         Tcl_SetIntObj(resultPtr, size);
  3071.         break;
  3072.     }
  3073.         case 8: {         /*startsearch*/
  3074.         ArraySearch *searchPtr;
  3075.  
  3076.         if (objc != 3) {
  3077.             Tcl_WrongNumArgs(interp, 2, objv, "arrayName");
  3078.         return TCL_ERROR;
  3079.         }
  3080.         if (notArray) {
  3081.             goto error;
  3082.         }
  3083.         searchPtr = (ArraySearch *) ckalloc(sizeof(ArraySearch));
  3084.         if (varPtr->searchPtr == NULL) {
  3085.             searchPtr->id = 1;
  3086.         Tcl_AppendStringsToObj(resultPtr, "s-1-", varName,
  3087.                 (char *) NULL);
  3088.         } else {
  3089.             char string[20];
  3090.  
  3091.         searchPtr->id = varPtr->searchPtr->id + 1;
  3092.         TclFormatInt(string, searchPtr->id);
  3093.         Tcl_AppendStringsToObj(resultPtr, "s-", string, "-", varName,
  3094.             (char *) NULL);
  3095.         }
  3096.         searchPtr->varPtr = varPtr;
  3097.         searchPtr->nextEntry = Tcl_FirstHashEntry(varPtr->value.tablePtr,
  3098.             &searchPtr->search);
  3099.         searchPtr->nextPtr = varPtr->searchPtr;
  3100.         varPtr->searchPtr = searchPtr;
  3101.         break;
  3102.     }
  3103.     }
  3104.     return TCL_OK;
  3105.  
  3106.     error:
  3107.     Tcl_AppendStringsToObj(resultPtr, "\"", varName, "\" isn't an array",
  3108.         (char *) NULL);
  3109.     return TCL_ERROR;
  3110. }
  3111.  
  3112. /*
  3113.  *----------------------------------------------------------------------
  3114.  *
  3115.  * MakeUpvar --
  3116.  *
  3117.  *    This procedure does all of the work of the "global" and "upvar"
  3118.  *    commands.
  3119.  *
  3120.  * Results:
  3121.  *    A standard Tcl completion code. If an error occurs then an
  3122.  *    error message is left in iPtr->result.
  3123.  *
  3124.  * Side effects:
  3125.  *    The variable given by myName is linked to the variable in framePtr
  3126.  *    given by otherP1 and otherP2, so that references to myName are
  3127.  *    redirected to the other variable like a symbolic link.
  3128.  *
  3129.  *----------------------------------------------------------------------
  3130.  */
  3131.  
  3132. static int
  3133. MakeUpvar(iPtr, framePtr, otherP1, otherP2, otherFlags, myName, myFlags)
  3134.     Interp *iPtr;        /* Interpreter containing variables. Used
  3135.                  * for error messages, too. */
  3136.     CallFrame *framePtr;    /* Call frame containing "other" variable.
  3137.                  * NULL means use global :: context. */
  3138.     char *otherP1, *otherP2;    /* Two-part name of variable in framePtr. */
  3139.     int otherFlags;        /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
  3140.                  * indicates scope of "other" variable. */
  3141.     char *myName;        /* Name of variable which will refer to
  3142.                  * otherP1/otherP2. Must be a scalar. */
  3143.     int myFlags;        /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
  3144.                  * indicates scope of myName. */
  3145. {
  3146.     Tcl_HashEntry *hPtr;
  3147.     Var *otherPtr, *varPtr, *arrayPtr;
  3148.     CallFrame *varFramePtr;
  3149.     CallFrame *savedFramePtr = NULL;  /* Init. to avoid compiler warning. */
  3150.     Tcl_HashTable *tablePtr;
  3151.     Namespace *nsPtr, *altNsPtr, *dummyNsPtr;
  3152.     char *tail;
  3153.     int new, result;
  3154.  
  3155.     /*
  3156.      * Find "other" in "framePtr". If not looking up other in just the
  3157.      * current namespace, temporarily replace the current var frame
  3158.      * pointer in the interpreter in order to use TclLookupVar.
  3159.      */
  3160.  
  3161.     if (!(otherFlags & TCL_NAMESPACE_ONLY)) {
  3162.     savedFramePtr = iPtr->varFramePtr;
  3163.     iPtr->varFramePtr = framePtr;
  3164.     }
  3165.     otherPtr = TclLookupVar((Tcl_Interp *) iPtr, otherP1, otherP2,
  3166.         (otherFlags | TCL_LEAVE_ERR_MSG), "access",
  3167.             /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
  3168.     if (!(otherFlags & TCL_NAMESPACE_ONLY)) {
  3169.     iPtr->varFramePtr = savedFramePtr;
  3170.     }
  3171.     if (otherPtr == NULL) {
  3172.     return TCL_ERROR;
  3173.     }
  3174.  
  3175.     /*
  3176.      * Now create a hashtable entry for "myName". Create it as either a
  3177.      * namespace variable or as a local variable in a procedure call
  3178.      * frame. Interpret myName as a namespace variable if:
  3179.      *    1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag,
  3180.      *    2) there is no active frame (we're at the global :: scope),
  3181.      *    3) the active frame was pushed to define the namespace context
  3182.      *       for a "namespace eval" or "namespace inscope" command,
  3183.      *    4) the name has namespace qualifiers ("::"s).
  3184.      * If creating myName in the active procedure, look first in the
  3185.      * frame's array of compiler-allocated local variables, then in its
  3186.      * hashtable for runtime-created local variables. Create that
  3187.      * procedure's local variable hashtable if necessary.
  3188.      */
  3189.  
  3190.     varFramePtr = iPtr->varFramePtr;
  3191.     if ((myFlags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY))
  3192.             || (varFramePtr == NULL)
  3193.             || !varFramePtr->isProcCallFrame
  3194.             || (strstr(myName, "::") != NULL)) {
  3195.     result = TclGetNamespaceForQualName((Tcl_Interp *) iPtr, myName,
  3196.                 (Namespace *) NULL, (myFlags | TCL_LEAVE_ERR_MSG),
  3197.                 &nsPtr, &altNsPtr, &dummyNsPtr, &tail);
  3198.         if (result != TCL_OK) {
  3199.         return result;
  3200.         }
  3201.         if (nsPtr == NULL) {
  3202.             nsPtr = altNsPtr;
  3203.         }
  3204.         if (nsPtr == NULL) {
  3205.         Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"",
  3206.                 myName, "\": unknown namespace", (char *) NULL);
  3207.             return TCL_ERROR;
  3208.         }
  3209.     hPtr = Tcl_CreateHashEntry(&nsPtr->varTable, tail, &new);
  3210.     if (new) {
  3211.         varPtr = NewVar();
  3212.         Tcl_SetHashValue(hPtr, varPtr);
  3213.         varPtr->hPtr = hPtr;
  3214.             varPtr->nsPtr = nsPtr;
  3215.     } else {
  3216.         varPtr = (Var *) Tcl_GetHashValue(hPtr);
  3217.     }
  3218.     } else {            /* look in the call frame */
  3219.     Proc *procPtr = varFramePtr->procPtr;
  3220.     int localCt = procPtr->numCompiledLocals;
  3221.     CompiledLocal *localPtr = procPtr->firstLocalPtr;
  3222.     Var *localVarPtr = varFramePtr->compiledLocals;
  3223.     int nameLen = strlen(myName);
  3224.     int i;
  3225.  
  3226.     varPtr = NULL;
  3227.     for (i = 0;  i < localCt;  i++) {
  3228.         if (!localPtr->isTemp) {
  3229.         char *localName = localVarPtr->name;
  3230.         if ((myName[0] == localName[0])
  3231.                 && (nameLen == localPtr->nameLength)
  3232.                 && (strcmp(myName, localName) == 0)) {
  3233.             varPtr = localVarPtr;
  3234.             new = 0;
  3235.             break;
  3236.         }
  3237.         }
  3238.         localVarPtr++;
  3239.         localPtr = localPtr->nextPtr;
  3240.     }
  3241.     if (varPtr == NULL) {    /* look in frame's local var hashtable */
  3242.         tablePtr = varFramePtr->varTablePtr;
  3243.         if (tablePtr == NULL) {
  3244.         tablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
  3245.         Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS);
  3246.         varFramePtr->varTablePtr = tablePtr;
  3247.         }
  3248.         hPtr = Tcl_CreateHashEntry(tablePtr, myName, &new);
  3249.         if (new) {
  3250.         varPtr = NewVar();
  3251.         Tcl_SetHashValue(hPtr, varPtr);
  3252.         varPtr->hPtr = hPtr;
  3253.                 varPtr->nsPtr = varFramePtr->nsPtr;
  3254.         } else {
  3255.         varPtr = (Var *) Tcl_GetHashValue(hPtr);
  3256.         }
  3257.     }
  3258.     }
  3259.  
  3260.     if (!new) {
  3261.     /*
  3262.      * The variable already exists. Make sure this variable "varPtr"
  3263.      * isn't the same as "otherPtr" (avoid circular links). Also, if
  3264.      * it's not an upvar then it's an error. If it is an upvar, then
  3265.      * just disconnect it from the thing it currently refers to.
  3266.      */
  3267.  
  3268.     if (varPtr == otherPtr) {
  3269.         Tcl_SetResult((Tcl_Interp *) iPtr,
  3270.             "can't upvar from variable to itself", TCL_STATIC);
  3271.         return TCL_ERROR;
  3272.     }
  3273.     if (TclIsVarLink(varPtr)) {
  3274.         Var *linkPtr = varPtr->value.linkPtr;
  3275.         if (linkPtr == otherPtr) {
  3276.         return TCL_OK;
  3277.         }
  3278.         linkPtr->refCount--;
  3279.         if (TclIsVarUndefined(linkPtr)) {
  3280.         CleanupVar(linkPtr, (Var *) NULL);
  3281.         }
  3282.     } else if (!TclIsVarUndefined(varPtr)) {
  3283.         Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName,
  3284.         "\" already exists", (char *) NULL);
  3285.         return TCL_ERROR;
  3286.     } else if (varPtr->tracePtr != NULL) {
  3287.         Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName,
  3288.         "\" has traces: can't use for upvar", (char *) NULL);
  3289.         return TCL_ERROR;
  3290.     }
  3291.     }
  3292.     TclSetVarLink(varPtr);
  3293.     TclClearVarUndefined(varPtr);
  3294.     varPtr->value.linkPtr = otherPtr;
  3295.     otherPtr->refCount++;
  3296.     return TCL_OK;
  3297. }
  3298.  
  3299. /*
  3300.  *----------------------------------------------------------------------
  3301.  *
  3302.  * Tcl_UpVar --
  3303.  *
  3304.  *    This procedure links one variable to another, just like
  3305.  *    the "upvar" command.
  3306.  *
  3307.  * Results:
  3308.  *    A standard Tcl completion code.  If an error occurs then
  3309.  *    an error message is left in interp->result.
  3310.  *
  3311.  * Side effects:
  3312.  *    The variable in frameName whose name is given by varName becomes
  3313.  *    accessible under the name localName, so that references to
  3314.  *    localName are redirected to the other variable like a symbolic
  3315.  *    link.
  3316.  *
  3317.  *----------------------------------------------------------------------
  3318.  */
  3319.  
  3320. int
  3321. Tcl_UpVar(interp, frameName, varName, localName, flags)
  3322.     Tcl_Interp *interp;        /* Command interpreter in which varName is
  3323.                  * to be looked up. */
  3324.     char *frameName;        /* Name of the frame containing the source
  3325.                  * variable, such as "1" or "#0". */
  3326.     char *varName;        /* Name of a variable in interp to link to.
  3327.                  * May be either a scalar name or an
  3328.                  * element in an array. */
  3329.     char *localName;        /* Name of link variable. */
  3330.     int flags;            /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
  3331.                  * indicates scope of localName. */
  3332. {
  3333.     int result;
  3334.     CallFrame *framePtr;
  3335.     register char *p;
  3336.  
  3337.     result = TclGetFrame(interp, frameName, &framePtr);
  3338.     if (result == -1) {
  3339.     return TCL_ERROR;
  3340.     }
  3341.  
  3342.     /*
  3343.      * Figure out whether varName is an array reference, then call
  3344.      * MakeUpvar to do all the real work.
  3345.      */
  3346.  
  3347.     for (p = varName;  *p != '\0';  p++) {
  3348.     if (*p == '(') {
  3349.         char *openParen = p;
  3350.         do {
  3351.         p++;
  3352.         } while (*p != '\0');
  3353.         p--;
  3354.         if (*p != ')') {
  3355.         goto scalar;
  3356.         }
  3357.         *openParen = '\0';
  3358.         *p = '\0';
  3359.         result = MakeUpvar((Interp *) interp, framePtr, varName,
  3360.             openParen+1, 0, localName, flags);
  3361.         *openParen = '(';
  3362.         *p = ')';
  3363.         return result;
  3364.     }
  3365.     }
  3366.  
  3367.     scalar:
  3368.     return MakeUpvar((Interp *) interp, framePtr, varName, (char *) NULL,
  3369.         0, localName, flags);
  3370. }
  3371.  
  3372. /*
  3373.  *----------------------------------------------------------------------
  3374.  *
  3375.  * Tcl_UpVar2 --
  3376.  *
  3377.  *    This procedure links one variable to another, just like
  3378.  *    the "upvar" command.
  3379.  *
  3380.  * Results:
  3381.  *    A standard Tcl completion code.  If an error occurs then
  3382.  *    an error message is left in interp->result.
  3383.  *
  3384.  * Side effects:
  3385.  *    The variable in frameName whose name is given by part1 and
  3386.  *    part2 becomes accessible under the name localName, so that
  3387.  *    references to localName are redirected to the other variable
  3388.  *    like a symbolic link.
  3389.  *
  3390.  *----------------------------------------------------------------------
  3391.  */
  3392.  
  3393. int
  3394. Tcl_UpVar2(interp, frameName, part1, part2, localName, flags)
  3395.     Tcl_Interp *interp;        /* Interpreter containing variables.  Used
  3396.                  * for error messages too. */
  3397.     char *frameName;        /* Name of the frame containing the source
  3398.                  * variable, such as "1" or "#0". */
  3399.     char *part1, *part2;    /* Two parts of source variable name to
  3400.                  * link to. */
  3401.     char *localName;        /* Name of link variable. */
  3402.     int flags;            /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
  3403.                  * indicates scope of localName. */
  3404. {
  3405.     int result;
  3406.     CallFrame *framePtr;
  3407.  
  3408.     result = TclGetFrame(interp, frameName, &framePtr);
  3409.     if (result == -1) {
  3410.     return TCL_ERROR;
  3411.     }
  3412.     return MakeUpvar((Interp *) interp, framePtr, part1, part2, 0,
  3413.         localName, flags);
  3414. }
  3415.  
  3416. /*
  3417.  *----------------------------------------------------------------------
  3418.  *
  3419.  * Tcl_GetVariableFullName --
  3420.  *
  3421.  *    Given a Tcl_Var token returned by Tcl_FindNamespaceVar, this
  3422.  *    procedure appends to an object the namespace variable's full
  3423.  *    name, qualified by a sequence of parent namespace names.
  3424.  *
  3425.  * Results:
  3426.  *      None.
  3427.  *
  3428.  * Side effects:
  3429.  *      The variable's fully-qualified name is appended to the string
  3430.  *    representation of objPtr.
  3431.  *
  3432.  *----------------------------------------------------------------------
  3433.  */
  3434.  
  3435. void
  3436. Tcl_GetVariableFullName(interp, variable, objPtr)
  3437.     Tcl_Interp *interp;            /* Interpreter containing the variable. */
  3438.     Tcl_Var variable;        /* Token for the variable returned by a
  3439.                  * previous call to Tcl_FindNamespaceVar. */
  3440.     Tcl_Obj *objPtr;        /* Points to the object onto which the
  3441.                  * variable's full name is appended. */
  3442. {
  3443.     Interp *iPtr = (Interp *) interp;
  3444.     register Var *varPtr = (Var *) variable;
  3445.     char *name;
  3446.  
  3447.     /*
  3448.      * Add the full name of the containing namespace (if any), followed by
  3449.      * the "::" separator, then the variable name.
  3450.      */
  3451.  
  3452.     if (varPtr != NULL) {
  3453.     if (!TclIsVarArrayElement(varPtr)) {
  3454.         if (varPtr->nsPtr != NULL) {
  3455.         Tcl_AppendToObj(objPtr, varPtr->nsPtr->fullName, -1);
  3456.         if (varPtr->nsPtr != iPtr->globalNsPtr) {
  3457.             Tcl_AppendToObj(objPtr, "::", 2);
  3458.         }
  3459.         }
  3460.         if (varPtr->name != NULL) {
  3461.         Tcl_AppendToObj(objPtr, varPtr->name, -1);
  3462.         } else if (varPtr->hPtr != NULL) {
  3463.         name = Tcl_GetHashKey(varPtr->hPtr->tablePtr, varPtr->hPtr);
  3464.         Tcl_AppendToObj(objPtr, name, -1);
  3465.         }
  3466.     }
  3467.     }
  3468. }
  3469.  
  3470. /*
  3471.  *----------------------------------------------------------------------
  3472.  *
  3473.  * Tcl_GlobalObjCmd --
  3474.  *
  3475.  *    This object-based procedure is invoked to process the "global" Tcl
  3476.  *    command. See the user documentation for details on what it does.
  3477.  *
  3478.  * Results:
  3479.  *    A standard Tcl object result value.
  3480.  *
  3481.  * Side effects:
  3482.  *    See the user documentation.
  3483.  *
  3484.  *----------------------------------------------------------------------
  3485.  */
  3486.  
  3487. int
  3488. Tcl_GlobalObjCmd(dummy, interp, objc, objv)
  3489.     ClientData dummy;        /* Not used. */
  3490.     Tcl_Interp *interp;        /* Current interpreter. */
  3491.     int objc;            /* Number of arguments. */
  3492.     Tcl_Obj *CONST objv[];    /* Argument objects. */
  3493. {
  3494.     Interp *iPtr = (Interp *) interp;
  3495.     register Tcl_Obj *objPtr;
  3496.     char *varName;
  3497.     register char *tail;
  3498.     int result, i;
  3499.  
  3500.     if (objc < 2) {
  3501.     Tcl_WrongNumArgs(interp, 1, objv, "varName ?varName ...?");
  3502.     return TCL_ERROR;
  3503.     }
  3504.  
  3505.     /*
  3506.      * If we are not executing inside a Tcl procedure, just return.
  3507.      */
  3508.     
  3509.     if ((iPtr->varFramePtr == NULL)
  3510.         || !iPtr->varFramePtr->isProcCallFrame) {
  3511.     return TCL_OK;
  3512.     }
  3513.  
  3514.     for (i = 1;  i < objc;  i++) {
  3515.     /*
  3516.      * Make a local variable linked to its counterpart in the global ::
  3517.      * namespace.
  3518.      */
  3519.     
  3520.     objPtr = objv[i];
  3521.     varName = Tcl_GetStringFromObj(objPtr, (int *) NULL);
  3522.  
  3523.     /*
  3524.      * The variable name might have a scope qualifier, but the name for
  3525.          * the local "link" variable must be the simple name at the tail.
  3526.      */
  3527.  
  3528.     for (tail = varName;  *tail != '\0';  tail++) {
  3529.         /* empty body */
  3530.     }
  3531.         while ((tail > varName) && ((*tail != ':') || (*(tail-1) != ':'))) {
  3532.             tail--;
  3533.     }
  3534.         if (*tail == ':') {
  3535.             tail++;
  3536.     }
  3537.  
  3538.     /*
  3539.      * Link to the variable "varName" in the global :: namespace.
  3540.      */
  3541.     
  3542.     result = MakeUpvar(iPtr, (CallFrame *) NULL,
  3543.         varName, (char *) NULL, /*otherFlags*/ TCL_GLOBAL_ONLY,
  3544.             /*myName*/ tail, /*myFlags*/ 0);
  3545.     if (result != TCL_OK) {
  3546.         return result;
  3547.     }
  3548.     }
  3549.     return TCL_OK;
  3550. }
  3551.  
  3552. /*
  3553.  *----------------------------------------------------------------------
  3554.  *
  3555.  * Tcl_VariableObjCmd --
  3556.  *
  3557.  *    Invoked to implement the "variable" command that creates one or more
  3558.  *    global variables. Handles the following syntax:
  3559.  *
  3560.  *        variable ?name value...? name ?value?
  3561.  *
  3562.  *    One or more variables can be created. The variables are initialized
  3563.  *    with the specified values. The value for the last variable is
  3564.  *    optional.
  3565.  *
  3566.  *    If the variable does not exist, it is created and given the optional
  3567.  *    value. If it already exists, it is simply set to the optional
  3568.  *    value. Normally, "name" is an unqualified name, so it is created in
  3569.  *    the current namespace. If it includes namespace qualifiers, it can
  3570.  *    be created in another namespace.
  3571.  *
  3572.  *    If the variable command is executed inside a Tcl procedure, it
  3573.  *    creates a local variable linked to the newly-created namespace
  3574.  *    variable.
  3575.  *
  3576.  * Results:
  3577.  *    Returns TCL_OK if the variable is found or created. Returns
  3578.  *    TCL_ERROR if anything goes wrong.
  3579.  *
  3580.  * Side effects:
  3581.  *    If anything goes wrong, this procedure returns an error message
  3582.  *    as the result in the interpreter's result object.
  3583.  *
  3584.  *----------------------------------------------------------------------
  3585.  */
  3586.  
  3587. int
  3588. Tcl_VariableObjCmd(dummy, interp, objc, objv)
  3589.     ClientData dummy;        /* Not used. */
  3590.     Tcl_Interp *interp;        /* Current interpreter. */
  3591.     int objc;            /* Number of arguments. */
  3592.     Tcl_Obj *CONST objv[];    /* Argument objects. */
  3593. {
  3594.     Interp *iPtr = (Interp *) interp;
  3595.     char *varName, *tail;
  3596.     Var *varPtr, *arrayPtr;
  3597.     Tcl_Obj *varValuePtr;
  3598.     int i, result;
  3599.  
  3600.     for (i = 1;  i < objc;  i = i+2) {
  3601.     /*
  3602.      * Look up each variable in the current namespace context, creating
  3603.      * it if necessary.
  3604.      */
  3605.     
  3606.     varName = Tcl_GetStringFromObj(objv[i], (int *) NULL);
  3607.     varPtr = TclLookupVar(interp, varName, (char *) NULL,
  3608.                 (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "define",
  3609.                 /*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr);
  3610.     if (varPtr == NULL) {
  3611.         return TCL_ERROR;
  3612.     }
  3613.  
  3614.     /*
  3615.      * Mark the variable as a namespace variable and increment its 
  3616.      * reference count so that it will persist until its namespace is
  3617.      * destroyed or until the variable is unset.
  3618.      */
  3619.  
  3620.     if (!(varPtr->flags & VAR_NAMESPACE_VAR)) {
  3621.         varPtr->flags |= VAR_NAMESPACE_VAR;
  3622.         varPtr->refCount++;
  3623.     }
  3624.  
  3625.     /*
  3626.      * If a value was specified, set the variable to that value.
  3627.      * Otherwise, if the variable is new, leave it undefined.
  3628.      * (If the variable already exists and no value was specified,
  3629.      * leave its value unchanged; just create the local link if
  3630.      * we're in a Tcl procedure).
  3631.      */
  3632.  
  3633.     if (i+1 < objc) {    /* a value was specified */
  3634.         varValuePtr = Tcl_ObjSetVar2(interp, objv[i], (Tcl_Obj *) NULL,
  3635.             objv[i+1], (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG));
  3636.         if (varValuePtr == NULL) {
  3637.         return TCL_ERROR;
  3638.         }
  3639.     }
  3640.  
  3641.     /*
  3642.      * If we are executing inside a Tcl procedure, create a local
  3643.      * variable linked to the new namespace variable "varName".
  3644.      */
  3645.  
  3646.     if ((iPtr->varFramePtr != NULL)
  3647.             && iPtr->varFramePtr->isProcCallFrame) {
  3648.         /*
  3649.          * varName might have a scope qualifier, but the name for the
  3650.          * local "link" variable must be the simple name at the tail.
  3651.          */
  3652.  
  3653.         for (tail = varName;  *tail != '\0';  tail++) {
  3654.         /* empty body */
  3655.         }
  3656.         while ((tail > varName)
  3657.             && ((*tail != ':') || (*(tail-1) != ':'))) {
  3658.         tail--;
  3659.         }
  3660.         if (*tail == ':') {
  3661.         tail++;
  3662.         }
  3663.         
  3664.         /*
  3665.          * Create a local link "tail" to the variable "varName" in the
  3666.          * current namespace.
  3667.          */
  3668.         
  3669.         result = MakeUpvar(iPtr, (CallFrame *) NULL,
  3670.             /*otherP1*/ varName, /*otherP2*/ (char *) NULL,
  3671.                     /*otherFlags*/ TCL_NAMESPACE_ONLY,
  3672.             /*myName*/ tail, /*myFlags*/ 0);
  3673.         if (result != TCL_OK) {
  3674.         return result;
  3675.         }
  3676.     }
  3677.     }
  3678.     return TCL_OK;
  3679. }
  3680.  
  3681. /*
  3682.  *----------------------------------------------------------------------
  3683.  *
  3684.  * Tcl_UpvarObjCmd --
  3685.  *
  3686.  *    This object-based procedure is invoked to process the "upvar"
  3687.  *    Tcl command. See the user documentation for details on what it does.
  3688.  *
  3689.  * Results:
  3690.  *    A standard Tcl object result value.
  3691.  *
  3692.  * Side effects:
  3693.  *    See the user documentation.
  3694.  *
  3695.  *----------------------------------------------------------------------
  3696.  */
  3697.  
  3698.     /* ARGSUSED */
  3699. int
  3700. Tcl_UpvarObjCmd(dummy, interp, objc, objv)
  3701.     ClientData dummy;        /* Not used. */
  3702.     Tcl_Interp *interp;        /* Current interpreter. */
  3703.     int objc;            /* Number of arguments. */
  3704.     Tcl_Obj *CONST objv[];    /* Argument objects. */
  3705. {
  3706.     register Interp *iPtr = (Interp *) interp;
  3707.     CallFrame *framePtr;
  3708.     char *frameSpec, *otherVarName, *myVarName;
  3709.     register char *p;
  3710.     int result;
  3711.  
  3712.     if (objc < 3) {
  3713.     upvarSyntax:
  3714.     Tcl_WrongNumArgs(interp, 1, objv,
  3715.         "?level? otherVar localVar ?otherVar localVar ...?");
  3716.     return TCL_ERROR;
  3717.     }
  3718.  
  3719.     /*
  3720.      * Find the call frame containing each of the "other variables" to be
  3721.      * linked to. FAILS IF objv[1]'s STRING REP CONTAINS NULLS.
  3722.      */
  3723.  
  3724.     frameSpec = Tcl_GetStringFromObj(objv[1], (int *) NULL);
  3725.     result = TclGetFrame(interp, frameSpec, &framePtr);
  3726.     if (result == -1) {
  3727.     return TCL_ERROR;
  3728.     }
  3729.     objc -= result+1;
  3730.     if ((objc & 1) != 0) {
  3731.     goto upvarSyntax;
  3732.     }
  3733.     objv += result+1;
  3734.  
  3735.     /*
  3736.      * Iterate over each (other variable, local variable) pair.
  3737.      * Divide the other variable name into two parts, then call
  3738.      * MakeUpvar to do all the work of linking it to the local variable.
  3739.      */
  3740.  
  3741.     for ( ;  objc > 0;  objc -= 2, objv += 2) {
  3742.     myVarName = Tcl_GetStringFromObj(objv[1], (int *) NULL);
  3743.     otherVarName = Tcl_GetStringFromObj(objv[0], (int *) NULL);
  3744.     for (p = otherVarName;  *p != 0;  p++) {
  3745.         if (*p == '(') {
  3746.         char *openParen = p;
  3747.  
  3748.         do {
  3749.             p++;
  3750.         } while (*p != '\0');
  3751.         p--;
  3752.         if (*p != ')') {
  3753.             goto scalar;
  3754.         }
  3755.         *openParen = '\0';
  3756.         *p = '\0';
  3757.         result = MakeUpvar(iPtr, framePtr,
  3758.                 otherVarName, openParen+1, /*otherFlags*/ 0,
  3759.             myVarName, /*flags*/ 0);
  3760.         *openParen = '(';
  3761.         *p = ')';
  3762.         goto checkResult;
  3763.         }
  3764.     }
  3765.     scalar:
  3766.     result = MakeUpvar(iPtr, framePtr, otherVarName, (char *) NULL, 0,
  3767.             myVarName, /*flags*/ 0);
  3768.  
  3769.     checkResult:
  3770.     if (result != TCL_OK) {
  3771.         return TCL_ERROR;
  3772.     }
  3773.     }
  3774.     return TCL_OK;
  3775. }
  3776.  
  3777. /*
  3778.  *----------------------------------------------------------------------
  3779.  *
  3780.  * CallTraces --
  3781.  *
  3782.  *    This procedure is invoked to find and invoke relevant
  3783.  *    trace procedures associated with a particular operation on
  3784.  *    a variable. This procedure invokes traces both on the
  3785.  *    variable and on its containing array (where relevant).
  3786.  *
  3787.  * Results:
  3788.  *    The return value is NULL if no trace procedures were invoked, or
  3789.  *    if all the invoked trace procedures returned successfully.
  3790.  *    The return value is non-NULL if a trace procedure returned an
  3791.  *    error (in this case no more trace procedures were invoked after
  3792.  *    the error was returned). In this case the return value is a
  3793.  *    pointer to a static string describing the error.
  3794.  *
  3795.  * Side effects:
  3796.  *    Almost anything can happen, depending on trace; this procedure
  3797.  *    itself doesn't have any side effects.
  3798.  *
  3799.  *----------------------------------------------------------------------
  3800.  */
  3801.  
  3802. static char *
  3803. CallTraces(iPtr, arrayPtr, varPtr, part1, part2, flags)
  3804.     Interp *iPtr;        /* Interpreter containing variable. */
  3805.     register Var *arrayPtr;    /* Pointer to array variable that contains
  3806.                  * the variable, or NULL if the variable
  3807.                  * isn't an element of an array. */
  3808.     Var *varPtr;        /* Variable whose traces are to be
  3809.                  * invoked. */
  3810.     char *part1, *part2;    /* Variable's two-part name. */
  3811.     int flags;            /* Flags passed to trace procedures:
  3812.                  * indicates what's happening to variable,
  3813.                  * plus other stuff like TCL_GLOBAL_ONLY,
  3814.                  * TCL_NAMESPACE_ONLY, and
  3815.                  * TCL_INTERP_DESTROYED. May also contain
  3816.                  * TCL_PARSE_PART1, which should not be
  3817.                  * passed through to callbacks. */
  3818. {
  3819.     register VarTrace *tracePtr;
  3820.     ActiveVarTrace active;
  3821.     char *result, *openParen, *p;
  3822.     Tcl_DString nameCopy;
  3823.     int copiedName;
  3824.  
  3825.     /*
  3826.      * If there are already similar trace procedures active for the
  3827.      * variable, don't call them again.
  3828.      */
  3829.  
  3830.     if (varPtr->flags & VAR_TRACE_ACTIVE) {
  3831.     return NULL;
  3832.     }
  3833.     varPtr->flags |= VAR_TRACE_ACTIVE;
  3834.     varPtr->refCount++;
  3835.  
  3836.     /*
  3837.      * If the variable name hasn't been parsed into array name and
  3838.      * element, do it here.  If there really is an array element,
  3839.      * make a copy of the original name so that NULLs can be
  3840.      * inserted into it to separate the names (can't modify the name
  3841.      * string in place, because the string might get used by the
  3842.      * callbacks we invoke).
  3843.      */
  3844.  
  3845.     copiedName = 0;
  3846.     if (flags & TCL_PARSE_PART1) {
  3847.     for (p = part1; ; p++) {
  3848.         if (*p == 0) {
  3849.         break;
  3850.         }
  3851.         if (*p == '(') {
  3852.         openParen = p;
  3853.         do {
  3854.             p++;
  3855.         } while (*p != '\0');
  3856.         p--;
  3857.         if (*p == ')') {
  3858.             Tcl_DStringInit(&nameCopy);
  3859.             Tcl_DStringAppend(&nameCopy, part1, (p-part1));
  3860.             part2 = Tcl_DStringValue(&nameCopy)
  3861.                 + (openParen + 1 - part1);
  3862.             part2[-1] = 0;
  3863.             part1 = Tcl_DStringValue(&nameCopy);
  3864.             copiedName = 1;
  3865.         }
  3866.         break;
  3867.         }
  3868.     }
  3869.     }
  3870.     flags &= ~TCL_PARSE_PART1;
  3871.  
  3872.     /*
  3873.      * Invoke traces on the array containing the variable, if relevant.
  3874.      */
  3875.  
  3876.     result = NULL;
  3877.     active.nextPtr = iPtr->activeTracePtr;
  3878.     iPtr->activeTracePtr = &active;
  3879.     if (arrayPtr != NULL) {
  3880.     arrayPtr->refCount++;
  3881.     active.varPtr = arrayPtr;
  3882.     for (tracePtr = arrayPtr->tracePtr;  tracePtr != NULL;
  3883.         tracePtr = active.nextTracePtr) {
  3884.         active.nextTracePtr = tracePtr->nextPtr;
  3885.         if (!(tracePtr->flags & flags)) {
  3886.         continue;
  3887.         }
  3888.         result = (*tracePtr->traceProc)(tracePtr->clientData,
  3889.             (Tcl_Interp *) iPtr, part1, part2, flags);
  3890.         if (result != NULL) {
  3891.         if (flags & TCL_TRACE_UNSETS) {
  3892.             result = NULL;
  3893.         } else {
  3894.             goto done;
  3895.         }
  3896.         }
  3897.     }
  3898.     }
  3899.  
  3900.     /*
  3901.      * Invoke traces on the variable itself.
  3902.      */
  3903.  
  3904.     if (flags & TCL_TRACE_UNSETS) {
  3905.     flags |= TCL_TRACE_DESTROYED;
  3906.     }
  3907.     active.varPtr = varPtr;
  3908.     for (tracePtr = varPtr->tracePtr; tracePtr != NULL;
  3909.         tracePtr = active.nextTracePtr) {
  3910.     active.nextTracePtr = tracePtr->nextPtr;
  3911.     if (!(tracePtr->flags & flags)) {
  3912.         continue;
  3913.     }
  3914.     result = (*tracePtr->traceProc)(tracePtr->clientData,
  3915.         (Tcl_Interp *) iPtr, part1, part2, flags);
  3916.     if (result != NULL) {
  3917.         if (flags & TCL_TRACE_UNSETS) {
  3918.         result = NULL;
  3919.         } else {
  3920.         goto done;
  3921.         }
  3922.     }
  3923.     }
  3924.  
  3925.     /*
  3926.      * Restore the variable's flags, remove the record of our active
  3927.      * traces, and then return.
  3928.      */
  3929.  
  3930.     done:
  3931.     if (arrayPtr != NULL) {
  3932.     arrayPtr->refCount--;
  3933.     }
  3934.     if (copiedName) {
  3935.     Tcl_DStringFree(&nameCopy);
  3936.     }
  3937.     varPtr->flags &= ~VAR_TRACE_ACTIVE;
  3938.     varPtr->refCount--;
  3939.     iPtr->activeTracePtr = active.nextPtr;
  3940.     return result;
  3941. }
  3942.  
  3943. /*
  3944.  *----------------------------------------------------------------------
  3945.  *
  3946.  * NewVar --
  3947.  *
  3948.  *    Create a new heap-allocated variable that will eventually be
  3949.  *    entered into a hashtable.
  3950.  *
  3951.  * Results:
  3952.  *    The return value is a pointer to the new variable structure. It is
  3953.  *    marked as a scalar variable (and not a link or array variable). Its
  3954.  *    value initially is NULL. The variable is not part of any hash table
  3955.  *    yet. Since it will be in a hashtable and not in a call frame, its
  3956.  *    name field is set NULL. It is initially marked as undefined.
  3957.  *
  3958.  * Side effects:
  3959.  *    Storage gets allocated.
  3960.  *
  3961.  *----------------------------------------------------------------------
  3962.  */
  3963.  
  3964. static Var *
  3965. NewVar()
  3966. {
  3967.     register Var *varPtr;
  3968.  
  3969.     varPtr = (Var *) ckalloc(sizeof(Var));
  3970.     varPtr->value.objPtr = NULL;
  3971.     varPtr->name = NULL;
  3972.     varPtr->nsPtr = NULL;
  3973.     varPtr->hPtr = NULL;
  3974.     varPtr->refCount = 0;
  3975.     varPtr->tracePtr = NULL;
  3976.     varPtr->searchPtr = NULL;
  3977.     varPtr->flags = (VAR_SCALAR | VAR_UNDEFINED | VAR_IN_HASHTABLE);
  3978.     return varPtr;
  3979. }
  3980.  
  3981. /*
  3982.  *----------------------------------------------------------------------
  3983.  *
  3984.  * ParseSearchId --
  3985.  *
  3986.  *    This procedure translates from a string to a pointer to an
  3987.  *    active array search (if there is one that matches the string).
  3988.  *
  3989.  * Results:
  3990.  *    The return value is a pointer to the array search indicated
  3991.  *    by string, or NULL if there isn't one.  If NULL is returned,
  3992.  *    interp->result contains an error message.
  3993.  *
  3994.  * Side effects:
  3995.  *    None.
  3996.  *
  3997.  *----------------------------------------------------------------------
  3998.  */
  3999.  
  4000. static ArraySearch *
  4001. ParseSearchId(interp, varPtr, varName, string)
  4002.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  4003.     Var *varPtr;        /* Array variable search is for. */
  4004.     char *varName;        /* Name of array variable that search is
  4005.                  * supposed to be for. */
  4006.     char *string;        /* String containing id of search. Must have
  4007.                  * form "search-num-var" where "num" is a
  4008.                  * decimal number and "var" is a variable
  4009.                  * name. */
  4010. {
  4011.     char *end;
  4012.     int id;
  4013.     ArraySearch *searchPtr;
  4014.  
  4015.     /*
  4016.      * Parse the id into the three parts separated by dashes.
  4017.      */
  4018.  
  4019.     if ((string[0] != 's') || (string[1] != '-')) {
  4020.     syntax:
  4021.     Tcl_AppendResult(interp, "illegal search identifier \"", string,
  4022.         "\"", (char *) NULL);
  4023.     return NULL;
  4024.     }
  4025.     id = strtoul(string+2, &end, 10);
  4026.     if ((end == (string+2)) || (*end != '-')) {
  4027.     goto syntax;
  4028.     }
  4029.     if (strcmp(end+1, varName) != 0) {
  4030.     Tcl_AppendResult(interp, "search identifier \"", string,
  4031.         "\" isn't for variable \"", varName, "\"", (char *) NULL);
  4032.     return NULL;
  4033.     }
  4034.  
  4035.     /*
  4036.      * Search through the list of active searches on the interpreter
  4037.      * to see if the desired one exists.
  4038.      */
  4039.  
  4040.     for (searchPtr = varPtr->searchPtr; searchPtr != NULL;
  4041.         searchPtr = searchPtr->nextPtr) {
  4042.     if (searchPtr->id == id) {
  4043.         return searchPtr;
  4044.     }
  4045.     }
  4046.     Tcl_AppendResult(interp, "couldn't find search \"", string, "\"",
  4047.         (char *) NULL);
  4048.     return NULL;
  4049. }
  4050.  
  4051. /*
  4052.  *----------------------------------------------------------------------
  4053.  *
  4054.  * DeleteSearches --
  4055.  *
  4056.  *    This procedure is called to free up all of the searches
  4057.  *    associated with an array variable.
  4058.  *
  4059.  * Results:
  4060.  *    None.
  4061.  *
  4062.  * Side effects:
  4063.  *    Memory is released to the storage allocator.
  4064.  *
  4065.  *----------------------------------------------------------------------
  4066.  */
  4067.  
  4068. static void
  4069. DeleteSearches(arrayVarPtr)
  4070.     register Var *arrayVarPtr;        /* Variable whose searches are
  4071.                      * to be deleted. */
  4072. {
  4073.     ArraySearch *searchPtr;
  4074.  
  4075.     while (arrayVarPtr->searchPtr != NULL) {
  4076.     searchPtr = arrayVarPtr->searchPtr;
  4077.     arrayVarPtr->searchPtr = searchPtr->nextPtr;
  4078.     ckfree((char *) searchPtr);
  4079.     }
  4080. }
  4081.  
  4082. /*
  4083.  *----------------------------------------------------------------------
  4084.  *
  4085.  * TclDeleteVars --
  4086.  *
  4087.  *    This procedure is called to recycle all the storage space
  4088.  *    associated with a table of variables. For this procedure
  4089.  *    to work correctly, it must not be possible for any of the
  4090.  *    variables in the table to be accessed from Tcl commands
  4091.  *    (e.g. from trace procedures).
  4092.  *
  4093.  * Results:
  4094.  *    None.
  4095.  *
  4096.  * Side effects:
  4097.  *    Variables are deleted and trace procedures are invoked, if
  4098.  *    any are declared.
  4099.  *
  4100.  *----------------------------------------------------------------------
  4101.  */
  4102.  
  4103. void
  4104. TclDeleteVars(iPtr, tablePtr)
  4105.     Interp *iPtr;        /* Interpreter to which variables belong. */
  4106.     Tcl_HashTable *tablePtr;    /* Hash table containing variables to
  4107.                  * delete. */
  4108. {
  4109.     Tcl_Interp *interp = (Tcl_Interp *) iPtr;
  4110.     Tcl_HashSearch search;
  4111.     Tcl_HashEntry *hPtr;
  4112.     register Var *varPtr;
  4113.     Var *linkPtr;
  4114.     int flags;
  4115.     ActiveVarTrace *activePtr;
  4116.     Tcl_Obj *objPtr;
  4117.     Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
  4118.  
  4119.     /*
  4120.      * Determine what flags to pass to the trace callback procedures.
  4121.      */
  4122.  
  4123.     flags = TCL_TRACE_UNSETS;
  4124.     if (tablePtr == &iPtr->globalNsPtr->varTable) {
  4125.     flags |= (TCL_INTERP_DESTROYED | TCL_GLOBAL_ONLY);
  4126.     } else if (tablePtr == &currNsPtr->varTable) {
  4127.     flags |= TCL_NAMESPACE_ONLY;
  4128.     }
  4129.  
  4130.     for (hPtr = Tcl_FirstHashEntry(tablePtr, &search);  hPtr != NULL;
  4131.         hPtr = Tcl_NextHashEntry(&search)) {
  4132.     varPtr = (Var *) Tcl_GetHashValue(hPtr);
  4133.  
  4134.     /*
  4135.      * For global/upvar variables referenced in procedures, decrement
  4136.      * the reference count on the variable referred to, and free
  4137.      * the referenced variable if it's no longer needed. Don't delete
  4138.      * the hash entry for the other variable if it's in the same table
  4139.      * as us: this will happen automatically later on.
  4140.      */
  4141.  
  4142.     if (TclIsVarLink(varPtr)) {
  4143.         linkPtr = varPtr->value.linkPtr;
  4144.         linkPtr->refCount--;
  4145.         if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
  4146.             && (linkPtr->tracePtr == NULL)
  4147.             && (linkPtr->flags & VAR_IN_HASHTABLE)) {
  4148.         if (linkPtr->hPtr == NULL) {
  4149.             ckfree((char *) linkPtr);
  4150.         } else if (linkPtr->hPtr->tablePtr != tablePtr) {
  4151.             Tcl_DeleteHashEntry(linkPtr->hPtr);
  4152.             ckfree((char *) linkPtr);
  4153.         }
  4154.         }
  4155.     }
  4156.  
  4157.     /*
  4158.      * Invoke traces on the variable that is being deleted, then
  4159.      * free up the variable's space (no need to free the hash entry
  4160.      * here, unless we're dealing with a global variable: the
  4161.      * hash entries will be deleted automatically when the whole
  4162.      * table is deleted). Note that we give CallTraces the variable's
  4163.      * fully-qualified name so that any called trace procedures can
  4164.      * refer to these variables being deleted.
  4165.      */
  4166.  
  4167.     if (varPtr->tracePtr != NULL) {
  4168.         objPtr = Tcl_NewObj();
  4169.         Tcl_IncrRefCount(objPtr); /* until done with traces */
  4170.         Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr);
  4171.         (void) CallTraces(iPtr, (Var *) NULL, varPtr,
  4172.             Tcl_GetStringFromObj(objPtr, (int *) NULL),
  4173.             (char *) NULL, flags);
  4174.         Tcl_DecrRefCount(objPtr); /* free no longer needed obj */
  4175.  
  4176.         while (varPtr->tracePtr != NULL) {
  4177.         VarTrace *tracePtr = varPtr->tracePtr;
  4178.         varPtr->tracePtr = tracePtr->nextPtr;
  4179.         ckfree((char *) tracePtr);
  4180.         }
  4181.         for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
  4182.             activePtr = activePtr->nextPtr) {
  4183.         if (activePtr->varPtr == varPtr) {
  4184.             activePtr->nextTracePtr = NULL;
  4185.         }
  4186.         }
  4187.     }
  4188.         
  4189.     if (TclIsVarArray(varPtr)) {
  4190.         DeleteArray(iPtr, Tcl_GetHashKey(tablePtr, hPtr), varPtr,
  4191.                 flags);
  4192.     }
  4193.     if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) {
  4194.         objPtr = varPtr->value.objPtr;
  4195.         TclDecrRefCount(objPtr);
  4196.         varPtr->value.objPtr = NULL;
  4197.     }
  4198.     varPtr->hPtr = NULL;
  4199.     varPtr->tracePtr = NULL;
  4200.     TclSetVarUndefined(varPtr);
  4201.     TclSetVarScalar(varPtr);
  4202.  
  4203.     /*
  4204.      * If the variable was a namespace variable, decrement its 
  4205.      * reference count. We are in the process of destroying its
  4206.      * namespace so that namespace will no longer "refer" to the
  4207.      * variable.
  4208.      */
  4209.  
  4210.     if (varPtr->flags & VAR_NAMESPACE_VAR) {
  4211.         varPtr->flags &= ~VAR_NAMESPACE_VAR;
  4212.         varPtr->refCount--;
  4213.     }
  4214.  
  4215.     /*
  4216.      * Recycle the variable's memory space if there aren't any upvar's
  4217.      * pointing to it. If there are upvars to this variable, then the
  4218.      * variable will get freed when the last upvar goes away.
  4219.      */
  4220.  
  4221.     if (varPtr->refCount == 0) {
  4222.         ckfree((char *) varPtr); /* this Var must be VAR_IN_HASHTABLE */
  4223.     }
  4224.     }
  4225.     Tcl_DeleteHashTable(tablePtr);
  4226. }
  4227.  
  4228. /*
  4229.  *----------------------------------------------------------------------
  4230.  *
  4231.  * TclDeleteCompiledLocalVars --
  4232.  *
  4233.  *    This procedure is called to recycle storage space associated with
  4234.  *    the compiler-allocated array of local variables in a procedure call
  4235.  *    frame. This procedure resembles TclDeleteVars above except that each
  4236.  *    variable is stored in a call frame and not a hash table. For this
  4237.  *    procedure to work correctly, it must not be possible for any of the
  4238.  *    variable in the table to be accessed from Tcl commands (e.g. from
  4239.  *    trace procedures).
  4240.  *
  4241.  * Results:
  4242.  *    None.
  4243.  *
  4244.  * Side effects:
  4245.  *    Variables are deleted and trace procedures are invoked, if
  4246.  *    any are declared.
  4247.  *
  4248.  *----------------------------------------------------------------------
  4249.  */
  4250.  
  4251. void
  4252. TclDeleteCompiledLocalVars(iPtr, framePtr)
  4253.     Interp *iPtr;        /* Interpreter to which variables belong. */
  4254.     CallFrame *framePtr;    /* Procedure call frame containing
  4255.                  * compiler-assigned local variables to
  4256.                  * delete. */
  4257. {
  4258.     register Var *varPtr;
  4259.     int flags;            /* Flags passed to trace procedures. */
  4260.     Var *linkPtr;
  4261.     ActiveVarTrace *activePtr;
  4262.     int numLocals, i;
  4263.  
  4264.     flags = TCL_TRACE_UNSETS;
  4265.     numLocals = framePtr->numCompiledLocals;
  4266.     varPtr = framePtr->compiledLocals;
  4267.     for (i = 0;  i < numLocals;  i++) {
  4268.     /*
  4269.      * For global/upvar variables referenced in procedures, decrement
  4270.      * the reference count on the variable referred to, and free
  4271.      * the referenced variable if it's no longer needed. Don't delete
  4272.      * the hash entry for the other variable if it's in the same table
  4273.      * as us: this will happen automatically later on.
  4274.      */
  4275.  
  4276.     if (TclIsVarLink(varPtr)) {
  4277.         linkPtr = varPtr->value.linkPtr;
  4278.         linkPtr->refCount--;
  4279.         if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr)
  4280.             && (linkPtr->tracePtr == NULL)
  4281.             && (linkPtr->flags & VAR_IN_HASHTABLE)) {
  4282.         if (linkPtr->hPtr == NULL) {
  4283.             ckfree((char *) linkPtr);
  4284.         } else {
  4285.             Tcl_DeleteHashEntry(linkPtr->hPtr);
  4286.             ckfree((char *) linkPtr);
  4287.         }
  4288.         }
  4289.     }
  4290.  
  4291.     /*
  4292.      * Invoke traces on the variable that is being deleted. Then delete
  4293.      * the variable's trace records.
  4294.      */
  4295.  
  4296.     if (varPtr->tracePtr != NULL) {
  4297.         (void) CallTraces(iPtr, (Var *) NULL, varPtr,
  4298.             varPtr->name, (char *) NULL, flags);
  4299.         while (varPtr->tracePtr != NULL) {
  4300.         VarTrace *tracePtr = varPtr->tracePtr;
  4301.         varPtr->tracePtr = tracePtr->nextPtr;
  4302.         ckfree((char *) tracePtr);
  4303.         }
  4304.         for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
  4305.             activePtr = activePtr->nextPtr) {
  4306.         if (activePtr->varPtr == varPtr) {
  4307.             activePtr->nextTracePtr = NULL;
  4308.         }
  4309.         }
  4310.     }
  4311.  
  4312.         /*
  4313.      * Now if the variable is an array, delete its element hash table.
  4314.      * Otherwise, if it's a scalar variable, decrement the ref count
  4315.      * of its value.
  4316.      */
  4317.         
  4318.     if (TclIsVarArray(varPtr) && (varPtr->value.tablePtr != NULL)) {
  4319.         DeleteArray(iPtr, varPtr->name, varPtr, flags);
  4320.     }
  4321.     if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) {
  4322.         TclDecrRefCount(varPtr->value.objPtr);
  4323.         varPtr->value.objPtr = NULL;
  4324.     }
  4325.     varPtr->hPtr = NULL;
  4326.     varPtr->tracePtr = NULL;
  4327.     TclSetVarUndefined(varPtr);
  4328.     TclSetVarScalar(varPtr);
  4329.     varPtr++;
  4330.     }
  4331. }
  4332.  
  4333. /*
  4334.  *----------------------------------------------------------------------
  4335.  *
  4336.  * DeleteArray --
  4337.  *
  4338.  *    This procedure is called to free up everything in an array
  4339.  *    variable.  It's the caller's responsibility to make sure
  4340.  *    that the array is no longer accessible before this procedure
  4341.  *    is called.
  4342.  *
  4343.  * Results:
  4344.  *    None.
  4345.  *
  4346.  * Side effects:
  4347.  *    All storage associated with varPtr's array elements is deleted
  4348.  *    (including the array's hash table). Deletion trace procedures for
  4349.  *    array elements are invoked, then deleted. Any pending traces for
  4350.  *    array elements are also deleted.
  4351.  *
  4352.  *----------------------------------------------------------------------
  4353.  */
  4354.  
  4355. static void
  4356. DeleteArray(iPtr, arrayName, varPtr, flags)
  4357.     Interp *iPtr;            /* Interpreter containing array. */
  4358.     char *arrayName;            /* Name of array (used for trace
  4359.                      * callbacks). */
  4360.     Var *varPtr;            /* Pointer to variable structure. */
  4361.     int flags;                /* Flags to pass to CallTraces:
  4362.                      * TCL_TRACE_UNSETS and sometimes
  4363.                      * TCL_INTERP_DESTROYED,
  4364.                      * TCL_NAMESPACE_ONLY, or
  4365.                      * TCL_GLOBAL_ONLY. */
  4366. {
  4367.     Tcl_HashSearch search;
  4368.     register Tcl_HashEntry *hPtr;
  4369.     register Var *elPtr;
  4370.     ActiveVarTrace *activePtr;
  4371.     Tcl_Obj *objPtr;
  4372.  
  4373.     DeleteSearches(varPtr);
  4374.     for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search);
  4375.         hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {
  4376.     elPtr = (Var *) Tcl_GetHashValue(hPtr);
  4377.     if (TclIsVarScalar(elPtr) && (elPtr->value.objPtr != NULL)) {
  4378.         objPtr = elPtr->value.objPtr;
  4379.         TclDecrRefCount(objPtr);
  4380.         elPtr->value.objPtr = NULL;
  4381.     }
  4382.     elPtr->hPtr = NULL;
  4383.     if (elPtr->tracePtr != NULL) {
  4384.         elPtr->flags &= ~VAR_TRACE_ACTIVE;
  4385.         (void) CallTraces(iPtr, (Var *) NULL, elPtr, arrayName,
  4386.             Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), flags);
  4387.         while (elPtr->tracePtr != NULL) {
  4388.         VarTrace *tracePtr = elPtr->tracePtr;
  4389.         elPtr->tracePtr = tracePtr->nextPtr;
  4390.         ckfree((char *) tracePtr);
  4391.         }
  4392.         for (activePtr = iPtr->activeTracePtr; activePtr != NULL;
  4393.             activePtr = activePtr->nextPtr) {
  4394.         if (activePtr->varPtr == elPtr) {
  4395.             activePtr->nextTracePtr = NULL;
  4396.         }
  4397.         }
  4398.     }
  4399.     TclSetVarUndefined(elPtr);
  4400.     TclSetVarScalar(elPtr);
  4401.     if (elPtr->refCount == 0) {
  4402.         ckfree((char *) elPtr); /* element Vars are VAR_IN_HASHTABLE */
  4403.     }
  4404.     }
  4405.     Tcl_DeleteHashTable(varPtr->value.tablePtr);
  4406.     ckfree((char *) varPtr->value.tablePtr);
  4407. }
  4408.  
  4409. /*
  4410.  *----------------------------------------------------------------------
  4411.  *
  4412.  * CleanupVar --
  4413.  *
  4414.  *    This procedure is called when it looks like it may be OK to free up
  4415.  *    a variable's storage. If the variable is in a hashtable, its Var
  4416.  *    structure and hash table entry will be freed along with those of its
  4417.  *    containing array, if any. This procedure is called, for example,
  4418.  *    when a trace on a variable deletes a variable.
  4419.  *
  4420.  * Results:
  4421.  *    None.
  4422.  *
  4423.  * Side effects:
  4424.  *    If the variable (or its containing array) really is dead and in a
  4425.  *    hashtable, then its Var structure, and possibly its hash table
  4426.  *    entry, is freed up.
  4427.  *
  4428.  *----------------------------------------------------------------------
  4429.  */
  4430.  
  4431. static void
  4432. CleanupVar(varPtr, arrayPtr)
  4433.     Var *varPtr;        /* Pointer to variable that may be a
  4434.                  * candidate for being expunged. */
  4435.     Var *arrayPtr;        /* Array that contains the variable, or
  4436.                  * NULL if this variable isn't an array
  4437.                  * element. */
  4438. {
  4439.     if (TclIsVarUndefined(varPtr) && (varPtr->refCount == 0)
  4440.         && (varPtr->tracePtr == NULL)
  4441.         && (varPtr->flags & VAR_IN_HASHTABLE)) {
  4442.     if (varPtr->hPtr != NULL) {
  4443.         Tcl_DeleteHashEntry(varPtr->hPtr);
  4444.     }
  4445.     ckfree((char *) varPtr);
  4446.     }
  4447.     if (arrayPtr != NULL) {
  4448.     if (TclIsVarUndefined(arrayPtr) && (arrayPtr->refCount == 0)
  4449.         && (arrayPtr->tracePtr == NULL)
  4450.             && (arrayPtr->flags & VAR_IN_HASHTABLE)) {
  4451.         if (arrayPtr->hPtr != NULL) {
  4452.         Tcl_DeleteHashEntry(arrayPtr->hPtr);
  4453.         }
  4454.         ckfree((char *) arrayPtr);
  4455.     }
  4456.     }
  4457. }
  4458. /*
  4459.  *----------------------------------------------------------------------
  4460.  *
  4461.  * VarErrMsg --
  4462.  *
  4463.  *      Generate a reasonable error message describing why a variable
  4464.  *      operation failed.
  4465.  *
  4466.  * Results:
  4467.  *      None.
  4468.  *
  4469.  * Side effects:
  4470.  *      Interp->result is reset to hold a message identifying the
  4471.  *      variable given by part1 and part2 and describing why the
  4472.  *      variable operation failed.
  4473.  *
  4474.  *----------------------------------------------------------------------
  4475.  */
  4476.  
  4477. static void
  4478. VarErrMsg(interp, part1, part2, operation, reason)
  4479.     Tcl_Interp *interp;         /* Interpreter in which to record message. */
  4480.     char *part1, *part2;        /* Variable's two-part name. */
  4481.     char *operation;            /* String describing operation that failed,
  4482.                                  * e.g. "read", "set", or "unset". */
  4483.     char *reason;               /* String describing why operation failed. */
  4484. {
  4485.     Tcl_ResetResult(interp);
  4486.     Tcl_AppendResult(interp, "can't ", operation, " \"", part1,
  4487.              (char *) NULL);
  4488.     if (part2 != NULL) {
  4489.         Tcl_AppendResult(interp, "(", part2, ")", (char *) NULL);
  4490.     }
  4491.     Tcl_AppendResult(interp, "\": ", reason, (char *) NULL);
  4492. }
  4493.